1

I imagine this is a common issue, but googling around hasn't presented a solution. I'm just having some trouble loading a library.

The source that I have for the library is utilizing static loading, which is fine. The rest of the libraries I am using are loaded dynamically.

The problem is that my program is now being loaded up as a library (it is a plugin), by a different application (a host). This means that the directory for the HOST executable, is NOT the program directory for my application.

The library that is being statically loaded (just a simple library for font rendering), is inside of my program's directory, and when loading my software as a plugin, it is not found. When I load up my software as a 'standalone' program (without a host), there is no issue.

I was able to resolve the issue by putting the 'missing' library into the folder for the host application, but this is a bad solution.

I was also able to resolve it by providing a direct path to the name of the library, but this is also a bad solution. I do not know where the end user will be installing my software.

Is there any way around this issue without having to rewrite the code to use dynamic loading?

To continue using static loading, must the library be registered? I think that registering this library is too invasive, as other programs may be using a different version of it.

const
  ft_lib = 'freetype6.dll';  //here is our problem. I could put a direct path
                             //here, to fix it, but I will not know this path
                             //on an end-user's machine

type
  FT_Library = Pointer;

function  FT_Init_FreeType(out alibrary : FT_Library ) : FT_Error;
  cdecl; external ft_lib name 'FT_Init_FreeType';
AudioGL
  • 494
  • 4
  • 18
  • What you describe is also dynamic linking. http://stackoverflow.com/questions/4153786/difference-between-static-linking-and-dynamic-linking If you really want to statically link the library, you don't need a dll, but the source code (or in case it is not Delphi, something the linker can get while compiling your program, for example .obj files). – jachguate Mar 06 '13 at 06:52
  • I'm sorry, I hope you don't mind if I fix up the question a bit. I meant static vs dynamic LOADING. :/ – AudioGL Mar 06 '13 at 06:54
  • See also this answer to the question [`"Delphi LoadLibrary Failing to find DLL other directory - any good options?"`](http://stackoverflow.com/a/2545212/576719). – LU RD Mar 06 '13 at 07:03
  • Thanks, but LoadLibrary _finds_ the .dll's in my application, without any hassle. It is the statically loaded .dll that is giving me trouble. What bothers me, it that I can _define_ the path for loadlibrary in code, dynamically. But with the static loading method, I can not define the path at runtime. – AudioGL Mar 06 '13 at 07:23
  • The term static is confusing. That's why MS don't use that term. Their official term is implicit linking. – David Heffernan Mar 06 '13 at 07:50
  • Can you fix the host application ? It seems to use `LoadLibrary` call to load your application, and that is deprecated and limited - as you just told us. Host application should use `LoadLibraryEx` specifying the relative alternate DLL search, so that DLL's for your app would be searched in your folder, not the host's one. – Arioch 'The Mar 06 '13 at 09:25
  • It's the sort of application where there are many hosts available, each coded to varying degrees of quality :) TBH, I've already rewritten most of the freetype library loader to work properly, in any situation. – AudioGL Mar 06 '13 at 09:55

2 Answers2

5

The program loader looks for DLLs on the system path. Just make sure that your freetype6.dll (and the DLLs that it requires) is either in the same directory as the host exe, or is in a directory that is in the file path (PATH environment variable).

For reference: http://msdn.microsoft.com/en-us/library/7d83bc18(v=vs.71).aspx

dthorpe
  • 35,318
  • 5
  • 75
  • 119
  • Thank you, I had not sorted out the PATH environment variable yet. My main issue is that up to this point, I've never had to _change_ anything in Windows (except for the occasional registry entry), and I'm hesitant to start doing it! – AudioGL Mar 06 '13 at 07:29
  • 1
    Modifying PATH is very heavyweight. It's system wide. I'd favour an approach local to your process. – David Heffernan Mar 06 '13 at 07:35
  • Using PATH fails to work as soon as two apps on the system try to do it that way. DLL hell I think is the colloquial term. – David Heffernan Mar 06 '13 at 20:10
  • Copying the DLL to the exe bin directory is an even better solution. – dthorpe Mar 06 '13 at 21:19
  • Danny, you're making a mess of this one. The plugin has to know about all its possible hosts? That's pretty demanding. And most likely the exe diretcory isn't writeable. – David Heffernan Mar 07 '13 at 07:19
  • The OP was asking whether there are any alternatives to rewriting their DLL to dynamically load all its dependencies. Yes, there are alternatives. Put the DLLs in the host exe directory (which is a process local solution), or put them on the path, or modify the path. Done, it works. Move on. Yes, there are gotchas with each of these, and they've all been thoroughly documented and argued over for the past 20 years. It's not like any of this is new material. – dthorpe Mar 08 '13 at 04:41
3

I would suggest that modifying PATH is a very invasive solution. I would recommend attempting to avoid that. You may be able to do that using SetDllDirectory. This will add a directory to the search path, but will make that change locally to your process.

Your host app should call SetDllDirectory immediately before loading your DLL. Then any dependencies of the DLL will be resolved using the modified search path. When the DLL has successfully loaded, call SetDllDirectory again to restore the search path to its default value.

If you aren't in control of the host then it might be tricky to implement this. You'd need to call SetDllDirectory in your DLL and then it would be too late. You could put another layer between the host and plugin. That layer could modify the DLL search path and then use LoadLibrary to load the DLL that used implicit linking.

The other obvious option is to stop using implicit linking. Use LoadLibrary to resolve all your dependencies. That's actually not as hard as it sounds.

In a modern Delphi you could use delay loading also. So long as the DLL search path is modified, before you call into the delay loaded imports, they will resolve.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Ah. This is the sort of answer I was hoping for. I'll try some testing with this. – AudioGL Mar 06 '13 at 07:47
  • I'm going to try some more testing, but it does seem like the only non-invasive way is to do a re-write that utilizes LoadLibrary. What I've found thus far is that I can't call SetDllDirectory _quickly_ enough (the plugin has already failed to load, even before executing an initialization block). The layer solution is interesting, but perhaps a bit much. Anyways, I appreciate the answer! – AudioGL Mar 06 '13 at 08:08
  • Finally, I'm using delphi 2006. Don't think delayed loading is an option until I upgrade. – AudioGL Mar 06 '13 at 08:13
  • I personally use a dedicated class to load and bind to DLLs. This wraps up all the boilerplate so that the user of the code has a cleaner job. – David Heffernan Mar 06 '13 at 08:24