locked
DllImport Relative path in a Class Library RRS feed

  • Question

  • Hi!, I'm working in a new project a Class Library project and I need to use DllImport, the problem is that I added a new folder in the project and inside of it a DLL "MyLibrary.dll" this Dll is a c++ dll.

    obviusly i cant use an absolute path, so, I tried to use a relative path, something like this:


    [DllImport(@"/MyFolder/MyLibrary.dll")]
    public static extern void MyFunction();
    but still i get an exception DllNotFoundException.

    How can i know the correct relative path for that file?

    Do I need add the file in other way?

    Thank you!


    Saturday, May 18, 2019 4:22 AM

Answers

  • You should not rely on relative (or absolute) paths in DllImport. Just use the DLL name. DllImport uses LoadLibrary which does a natural search for your DLL. In a normal situation you'd copy the DLL to your project's output directory (generally via a post-build event). Then the DLL will be found. In the rare cases where you want to use a subfolder you could use a relative path but note your path is a rooted path. Relative paths don't start with a /. But relative paths tend to not behave properly with LoadLibrary because it searches multiple paths. You can always change the search path of the app if you want to store dependencies in a child directory but I question the benefit of this.

    Michael Taylor http://www.michaeltaylorp3.net

    Monday, May 20, 2019 2:14 PM

All replies

  • If you already specified “Copy to Output Directory: Copy if newer” option in Properties panel for MyLibrary.dll, then try [DllImport(@".\MyFolder\MyLibrary.dll")].

    Saturday, May 18, 2019 4:57 PM
  • Hi!, thank you for the help, i changed the Property “Copy to Output Directory" to Copy if newer, and then y change my path like you said @".\MyFolder\MyLibrary.dll"

    but it doesn't work, can you explain me what is the diference between have "Copy if newer" in that property? and, What is the difference between my old and new path?  

    by the way, i found "Compilation Action" property which has:
    None, Compile, EmbeddedResource
    Content and Folder,

    i need change that property too, right?

    Saturday, May 18, 2019 8:47 PM
  • Hi,

    DllImport use the LoadLibrary api, one of the behavior of LoadLibrary is to load the file only once time, after each reference to the dll filename (without path) it using the loaded dll in memory.

    So the solution is to use LoadLibrary to load your dll file in memory at your application startup and then use only [DllImport("MyLibrary.dll"].

    I used this solution in an old project for loading a Lua DLL in 64 or 32 bits depending the application plateform. You can find the example in this file: https://github.com/ygrenier/tests/blob/master/PInvokeMultiPlatform/PInvokeMultiPlatform/Lua.cs . Sorry the documentation are in french, but normally the comments are in English.

    In the static constructor (invoked once the class is referenced in the code) I load the DLL, after I can reference [DllImport] with the name of the Library.

    Regards,


    Yan Grenier

    Merci de bien vouloir "Marquer comme réponse", les réponses qui ont répondues à votre question, et de noter les réponses que vous avez trouvé utiles.


    Monday, May 20, 2019 6:38 AM
  • You should not rely on relative (or absolute) paths in DllImport. Just use the DLL name. DllImport uses LoadLibrary which does a natural search for your DLL. In a normal situation you'd copy the DLL to your project's output directory (generally via a post-build event). Then the DLL will be found. In the rare cases where you want to use a subfolder you could use a relative path but note your path is a rooted path. Relative paths don't start with a /. But relative paths tend to not behave properly with LoadLibrary because it searches multiple paths. You can always change the search path of the app if you want to store dependencies in a child directory but I question the benefit of this.

    Michael Taylor http://www.michaeltaylorp3.net

    Monday, May 20, 2019 2:14 PM
  • Hi thank you for your answer!, I read more about this and your answer have so much sense but, when I try to find the file only with his name, i get exactly the same exception "DllNotFoundException", i think the error is in the file properties, maybe the file isn't configurated, I´ve this properties: Compilation Action, Copy to output directory and Include in the package. In the "Copy to output directory" property I set the value to Copy if newer.

    I think the error is that the file is not in the output directory and that's the reason why it never is found.

    What am I doing wrong?

    thanks

     
    Monday, May 20, 2019 5:18 PM
  • Hi I was  reading your answer and the code, and I've a question about it,

    Do you load the file in the output directory at runtime?, Does the code do exactly the same thing than put the value "Copy if newer" in "Copy to output directory" property?, 

    because i think the problem is that the file never is found because the file is not in the output directory, even if I put "Copy if newer" in the "Copy to output directory" property, and I dont know if i need set another file property too.

    I gonna try you code to watch the output, but if you can help with the previuos answers. I would understand better the solution to the problem. Thank you

    Monday, May 20, 2019 5:27 PM
  • The only way you'd have these options is if you added the DLL to your project file directly (like a content file). Is that what you did? In general we don't do that. We use a post build event to copy the DLL from wherever it resides to the output directory of the project. 

    To ensure the binary is available (assuming you aren't building it yourself) then we tend to create a root folder in the solution called Dependencies or something. Then we drop the binaries into that (or perhaps subfolders of it). We can then include those binaries in source control (if needed). The post build event copies from this directory to the project's output directory.

    Some things to be aware of.

    1. Application's determine the bitness of the process. If your DLL is 32-bit then your app must also be 32-bit. That is where the Platform setting in the project comes in. If your app is 64-bit then you need to ensure the DLL is also 64-bit otherwise it won't load.

    2. You can go to the output directory of your project and confirm (after the build) that the DLL got copied correctly. If it isn't then there the pathing you're using is wrong.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, May 20, 2019 5:29 PM
  • Hi!, thank you for the support and pattience I gonna describe what I did it

    I use the Dll with an absolue path to check if all works and it works perfectly, then I added the file directly inside the project, and set his properties like Copy to output directory in Copy if newer, actually I checked the output directory and the file is there, but I dont understand, why the project cant find it?, and, why are you using code? because when i use the absolute path I dont need extra code.

    if you need some pictures or extra information just tell me. 

    Thank you for the answer, and again pattience, I'm new trying doing this.

    Tuesday, May 21, 2019 2:19 AM
  • If the DLL is in the output directory then your DllImport should just be the DLL name, no path.

    [DllImport("MyLibrary.dll")]
    public static extern void MyFunction();
    Note that I'm assuming your import is correct other than the pathing because you said it worked but do note that there are other DllImport properties that may need to be set before the call will actually work correctly (calling convention, Unicode vs Ansi, etc). 


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, May 21, 2019 2:27 AM
  • Thank it works, the problem is My IDE, i was using Monodevelop and I cant execute the program in the IDE so I tried Directly in Terminal but, I forgot my project was in DEBUG, when i changed to RELEASE all works. THANK YOU!
    Tuesday, May 21, 2019 2:33 AM