Search Unity

DllNotFoundException for a DLL that is present

Discussion in 'Scripting' started by Antistone, Jun 11, 2015.

  1. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I'm compiling a native C++ DLL and using it as a plugin in a Unity game. After some work, my basic tests showed everything to be working fine; I was able to make calls to the DLL, pass information in both directions, and got expected results. I've done several iterations of adding new functions to the DLL, recompiling, and integrating them into the Unity game.

    But on this particular occasion, when I deleted the DLL and replaced with a newly-compiled version, my Unity build (windows 32-bit standalone) has started throwing an exception:

    DllNotFoundException: <filepath to dll>

    I browsed to the reported filepath in Windows Explorer, and there is a dll with the correct name in that directory.

    What might be going wrong?
     
  2. Duugu

    Duugu

    Joined:
    May 23, 2015
    Posts:
    241
    So, where did you save the dll and what does the code to import it looks like? :)
     
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    The DLL is in Assets/Plugins/x86

    The code referencing it is a series of declarations along the lines of:
    Code (CSharp):
    1.         [DllImport("mydll", EntryPoint = "gDownloadProgress")]
    2.         private static extern int gDownloadProgress(IntPtr item);
    But as I said, all of this used to work, so I don't see how my problem could be related to either of those.
     
  4. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    What specific changes have you made between the version that does not work and the new one? In particular, have you added any dependencies?

    You may need to use dependency walker to detect any unexpected dependencies that your dll now has. If there are dependencies, these must be registered on the system (read: add to GAC) or available in the currently running assembly's location. If this is the Unity editor, most likely here: C:\Program Files\Unity\Editor
     
    aparajithsairam likes this.
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Based on several tests adding and removing stuff, this error appears to be related to the addition of new calls to libcurl. However, adding libcurl.dll to the same location as my DLL does not seem to fix the problem.

    I'm not sure how to interpret the output of Dependency Walker, but it seems to be reporting (the same) several problems on both the working and non-working versions of my DLL, and identifies a large number of dependencies with names I don't recognize (again, in both).
     
  6. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Unfortunately, the dependency chain's automatic dll import will probably not look beside your dll. You will need to put the libcurl dll into the executing assembly bin. For the editor, that would be C:\Program Files\Unity\Editor. When you publish, you will need to move this dll into your own bin folder. You can read about this behavior but beware: it might as well be written in Latin.

    The assemblies you don't recognize are probably system assemblies and are likely registered. You could probably find them in the GAC. Since you've already determined the dependency that is causing the issue, you don't need to pursue that any further.

    I'm not sure it will work because I haven't tried it on unmanaged assemblies, but the fuslogvw can be really helpful in determining why assembles are not loading.
     
    Last edited: Jun 12, 2015
    aparajithsairam likes this.
  7. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I'm currently relying on testing a standalone build, not running in the editor.

    (In the editor, it seems once you use a DLL, it won't let you delete it unless you restart Unity entirely, which is a big pain if you're iterating rapidly. Plus, I'm currently building a 32-bit DLL but running under 64-bit windows; with standalone builds I can specify 32-bit target.)

    Looking at the build produced by Unity, I see a folder called "<appname>_Data", and inside that I see directories Managed, Mono, Plugins, and Resources. I don't see a "bin". Placing libcurl.dll inside a new directory named "bin" either inside or parallel to the data directory does not change my results.
     
  8. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    I use the term "bin" rather loosely. Historically, that is the directory where a program's binaries were located so I meant it to describe where the main executable lives.

    Okay, you'll need to find your executing assembly's location. From code you could try:
    Code (csharp):
    1. using System.Reflection;
    2. // ...
    3. Assembly.GetExecutingAssembly().Location
     
  9. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Assembly.GetExecutingAssembly().Location returns (...)\myapp\myapp_Data\Managed\Assembly-CSharp.dll

    Putting libcurl.dll in myapp\myapp_Data\Managed\ does not seem to help.

    I would have been fairly surprised if it did--why would the C# assembly location be the place that it looks for a DLL required by a native plugin? And even if it were, why is there not a more standardized process for handling this than writing some add-hoc reflection code into your app to figure out where to manually place the files?

    I'm also quite worried by the fact that the error message I'm getting (a DllNotFoundException for my top-level DLL) is so generic that if I happened to have multiple problems, I would have no way of knowing when I'd fixed one of them. For all I know, any or all of the solutions tried up to this point might have been sufficient to let Unity find libcurl.dll but there's some completely separate problem also going on.
     
  10. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    This surprises me.I thought we would get the top level assembly but I was wrong. You could look around this area for the main executable. That is likely where the assembly searcher is looking.

    It has more to do with where the computer thinks the current execution path is. The fact that you're running managed code isn't that important.

    Normally you would know where your main executable lives. I suggested this as a quick solution to finding the path since I'm not sure how standalone unity games execute.

    I sympathize empathize. It is a poor exception but my experience is that low level stuff often has poor exception messages.

    Quite right. My next suggestion is to try fuslogvw. Hopefully this will work with your unmanaged assembly. If not, you could resort to watching for references to libcurl.dll in filemon.
     
    Last edited: Jun 13, 2015
  11. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    In fact, I do know where my main executable lives. I hadn't realized you were trying to find the current working directory.

    Putting libcurl.dll into the same directory as my executable appears to have fixed the DllNotFoundException!

    (That's kind of a pain, but at least it works for now.)

    Thank you!


    (Note, in case someone else is dealing with this: the current working directory of a standalone build is different depending on whether you run the build directly or by using Unity's "build and run" command. If you run your build by double-clicking on it, the working directory is where the program is located. If you use Build & Run, I think it uses your Unity project's directory, but I might be remembering that wrong.)
     
    NicRule and eisenpony like this.
  12. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Sorry! That's what I get for not using precise terminology..

    I apologize for the GetExecutingAssembly red herring. I was remembering incorrectly and meant to point towards the AppDomain directory. In retrospect however, that is probably incorrect too. I suspect the Unity devs have the scripts running in a sandboxed AppDomain.

    Anyways, I thought you might be interested in this stackoverflow answer. I thought it did a good job of explaining, in plain language, how you can specify where to find the assembly.
     
  13. sgoodrow

    sgoodrow

    Joined:
    Sep 28, 2012
    Posts:
    150
    So aside from moving the DLL to be adjacent to the executable, there is on known solution to this problem?
     
  14. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Does the stack overflow answer above not help?
     
  15. sgoodrow

    sgoodrow

    Joined:
    Sep 28, 2012
    Posts:
    150
    Thank you eisenpony, I mistakenly overlooked that part of your comment. It looks like it might be fruitful, at least to create a temporary solution until the underlying problem gets resolved!

    I'll report back with my success/failure.
     
  16. bteitler

    bteitler

    Joined:
    May 11, 2014
    Posts:
    52
    Having the same issue where I have to move the DLLs adjacent to the executable. This is lame and a deal breaker for me.. Other plugins work, but mine (has one dependency, both built with Visual Studio 2015 Community) won't work unless its adjacent. I see it in the plugins folder but isn't found :(
     
  17. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Have you tried the AddDllDirectory method outlined in the stack overflow link?
     
  18. bteitler

    bteitler

    Joined:
    May 11, 2014
    Posts:
    52
    I ended up having to do a solution similar to add new library directories at runtime. This seems brittle and extremely lame to me that Unity still cannot natively handle chained dependent DLLs. Please fix.. clearly all it would take is Unity itself adding the library directory at runtime, but they are in the position to know exactly which directory that is for each version / platform moving forward, so they should be the ones doing it.