Recent

Author Topic: Move DLL from ParentFolder to ChildFolder ?  (Read 365 times)

jojo86

  • New member
  • *
  • Posts: 10
Move DLL from ParentFolder to ChildFolder ?
« on: December 05, 2018, 03:49:02 pm »
Hi,
I have a little question.
I did an application wich requires many DLL files (LibCairo with a lot of DLL files...)
So I would want to create a folder named "LibDLL" (for exemple) and put inside all my DLLs files.

I need a solution to say to the application : All DLLs you need are in the folder :
Code: Pascal  [Select]
  1.  ProgramDirectory + '\LibDLL\'

Thanx helping me !

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 515
    • Lebeau Software
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #1 on: December 05, 2018, 08:33:52 pm »
I need a solution to say to the application : All DLLs you need are in the folder :
Code: Pascal  [Select]
  1.  ProgramDirectory + '\LibDLL\'

Assuming you are using Windows, the Win32 API has SetDllDirectory() and AddDllDirectory() functions.

However, they work only if you dynamically load the DLLs in code at runtime using LoadLibrary/Ex(), and only if you load the DLLs using relative paths.  The best option in this situation is to simply load the DLLs using absolute paths instead, then you don't need to use those directory functions at all.  Simply retrieve your app's current folder at runtime (ie, GetModuleFileName(), PathRemoveFileSpec(), etc), then append the desired subfolder to that, and then append the DLL filenames to that as needed.

If you link to the DLLs statically at compile-time, there is no option to specify a folder before the DLLs are loaded at runtime, since your app's code is not running yet, so the folder must exist on the system's Search Path instead.

See Dynamic-Link Library Search Order for more details.
« Last Edit: December 05, 2018, 08:41:20 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

CCRDude

  • Sr. Member
  • ****
  • Posts: 446
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #2 on: December 05, 2018, 09:01:20 pm »
If you link to the DLLs statically at compile-time, there is no option to specify a folder before the DLLs are loaded at runtime, since your app's code is not running yet, so the folder must exist on the system's Search Path instead.

Not quite true any more for the past few versions of Windows :)
You can use the applications manifest to specify different load paths for dynamic link libraries linked statically.

I do this for having subfolders for x86 and x64 dlls (they're often named the same); here's the beginning of the manifest I use for the 32 bit version of such a situation:
Code: [Select]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="org.safer-networking.SpybotAntiBeacon" type="win32"/>
 <description>Anti-Beacon</description>
 <file name="libeay32.dll" loadFrom="x86/libeay32.dll" />
 <file name="ssleay32.dll" loadFrom="x86/ssleay32.dll" />
 <file name="sqlite3.dll" loadFrom="x86/sqlite3.dll" />

You would need different manifests for different outputs of course.

ASerge

  • Hero Member
  • *****
  • Posts: 998
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #3 on: December 06, 2018, 12:40:11 am »
So I would want to create a folder named "LibDLL" (for exemple) and put inside all my DLLs files.
I need a solution to say to the application : All DLLs you need are in the folder :
Code: Pascal  [Select]
  1.  ProgramDirectory + '\LibDLL\'
1. Use custom manifest for application (to add dependentAssembly).
Remove check "Use manifest resource" from project options (Application).
Make file (example) addon.rc in some folder "Res" with content: 1 24 "App.manifest".
Create file Res\App.manifest like this:
Code: XML  [Select]
  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  3.     <assemblyIdentity name="Test" processorArchitecture="*" version="1.0.0.0" type="win32" />
  4.     <asmv3:trustInfo>
  5.         <asmv3:security>
  6.             <asmv3:requestedPrivileges>
  7.                 <asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
  8.             </asmv3:requestedPrivileges>
  9.         </asmv3:security>
  10.     </asmv3:trustInfo>
  11.     <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  12.         <application>
  13.             <!-- Windows 10 and Windows Server 2016 -->
  14.             <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
  15.             <!-- Windows 8.1 and Windows Server 2012 R2 -->
  16.             <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
  17.             <!--  Windows 8 and Windows Server 2012 -->
  18.             <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
  19.             <!-- Windows 7 and Windows Server 2008 R2 -->
  20.             <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
  21.             <!-- Windows Vista and Windows Server 2008 -->
  22.             <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
  23.         </application>
  24.     </compatibility>
  25.     <dependency>
  26.         <dependentAssembly>
  27.             <assemblyIdentity type="win32" name="LibDLL" version="1.0.0.0" />
  28.         </dependentAssembly>
  29.     </dependency>
  30. </assembly>
Compile it with resource compiler (winres) to addon.res.
Include into you app by {$R 'Res\AddOn.res'}.

2. In LibDLL subfolder create LibDLL.manifest like this:
Code: XML  [Select]
  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  3.   <assemblyIdentity type="win32" name="LibDLL" version="1.0.0.0" />
  4.   <file name="SomeDll.dll" />
  5. </assembly>
Repeat file tag for each dll in you subfolder.

3. Create file Project.exe.config file in exe folder:
Code: XML  [Select]
  1. <configuration>  
  2.   <runtime>
  3.     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  4.       <probing privatePath="LibDLL" />
  5.     </assemblyBinding>
  6.   </runtime>
  7. </configuration>

Run you app :)
Not work on XP :(

CCRDude

  • Sr. Member
  • ****
  • Posts: 446
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #4 on: December 06, 2018, 07:39:52 am »
@ASerge: I tried that option as well before, but it requires three files instead of one line in one file (per DLL). Have you experienced any downsides in the folder being regarded as an assembly? I'm thinking of security issues mainly. Could someone override your "assembly" by providing an assembly with a "newer" version in a different folder?

CCRDude

  • Sr. Member
  • ****
  • Posts: 446
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #5 on: December 07, 2018, 10:33:34 am »
Interesting how issues arise in context... I'm now in a place where my solution seems to fail: I have a third party DLL that depends on other DLLs. I want them all in the x86 subfolder. Specifying each DLLs path using my file...loadFrom attributes does work when running the program from the debugger, but not when started e.g. from Total Commander (I assume it has to do with the working folder; my app changes its working folder already for cases where it's started with a different once specified, but that doesn't help for the statically dynamically bound external DLL).

(as another attempt at a workaround, I will update the code that uses this third party DLL to be dynamically loaded, so that binding will happen later during execution)

Does your solution help in these cases, @ASerge?

ASerge

  • Hero Member
  • *****
  • Posts: 998
Re: Move DLL from ParentFolder to ChildFolder ?
« Reply #6 on: December 07, 2018, 07:21:28 pm »
my app changes its working folder already for cases where it's started with a different once specified, ...
Does your solution help in these cases, @ASerge?
In my solution in Project.exe.config you can rename the <runtime> section to <windows> and use multiple paths in the privatePath separated by';'. Including relative paths of a kind "..\..\ ".