Error while loading Third party DLLs dependencies

Hi guys,

I’m trying for weeks to integrate a third-party library (GDAL) into a plugin.
This library depends from many other libraries (like PROJ for exemple).

Her is my code structure :
image
Binaries/ThirdParty/Win64 contains all dlls needed (gdal and all its dependencies)
Source/ThirdParty/Gdal/Include/ contains all header files of gdal and all its dependencies
Source/ThirdParty/Gdal/Lib/ contains all libs needed (gdal and all its dependencies)

TerrainLoader.Build.cs

public class TerrainLoader : ModuleRules
{
	public TerrainLoader(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
		
		PublicIncludePaths.AddRange(
			new string[] {
				// ... add public include paths required here ...
			}
			);
				
		
		PrivateIncludePaths.AddRange(
			new string[] {
				// ... add other private include paths required here ...
			}
			);
			
		
		PublicDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
				"CoreUObject",
				"Engine",
				"Projects",
				"Gdal",
				"UElibPNG",
				"zlib",
				"OpenSSL"
				// ... add other public dependencies that you statically link with here ...
			}
			);
			
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"MeshConversion",
				"MeshDescription",
				"StaticMeshDescription"
				// ... add private dependencies that you statically link with here ...	
			}
			);
		
		
		DynamicallyLoadedModuleNames.AddRange(
			new string[]
			{
				// ... add any modules that your module loads dynamically here ...
			}
			);
	}
}

“UElibPNG”, zlib" and “OpenSSL” are 3 dependencies of GDAL allready used by the engine, so instead of reimporting them, i had these modules as dependencies.

public class Gdal : ModuleRules
{
	public Gdal(ReadOnlyTargetRules Target) : base(Target)
	{
		bEnableUndefinedIdentifierWarnings = false;
		
		Type = ModuleType.External;

		// Header files (platform independent)
		PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Include"));
		PublicSystemIncludePaths.Add(Path.Combine(ModuleDirectory, "Include"));
		
		// Libs
		List<string> publicAdditionalLibsNames = new List<string>();
		publicAdditionalLibsNames.Add("charset.lib");
		publicAdditionalLibsNames.Add("freexl.lib");
		publicAdditionalLibsNames.Add("gdal.lib");
		publicAdditionalLibsNames.Add("geos.lib");
		publicAdditionalLibsNames.Add("geos_c.lib");
		publicAdditionalLibsNames.Add("geotiff_i.lib");
		publicAdditionalLibsNames.Add("gif.lib");
		publicAdditionalLibsNames.Add("hdf5.lib");
		publicAdditionalLibsNames.Add("hdf5_cpp.lib");
		publicAdditionalLibsNames.Add("hdf5_hl.lib");
		publicAdditionalLibsNames.Add("hdf5_hl_cpp.lib");
		publicAdditionalLibsNames.Add("iconv.lib");
		publicAdditionalLibsNames.Add("jpeg.lib");
		publicAdditionalLibsNames.Add("json-c.lib");
		publicAdditionalLibsNames.Add("json-c-static.lib");
		// publicAdditionalLibsNames.Add("libcrypto.lib");
		publicAdditionalLibsNames.Add("libcurl.lib");
		publicAdditionalLibsNames.Add("libecpg.lib");
		publicAdditionalLibsNames.Add("libecpg_compat.lib");
		publicAdditionalLibsNames.Add("libexpat.lib");
		publicAdditionalLibsNames.Add("libpgcommon.lib");
		publicAdditionalLibsNames.Add("libpgport.lib");
		publicAdditionalLibsNames.Add("libpgtypes.lib");
		// publicAdditionalLibsNames.Add("libpng16.lib");
		publicAdditionalLibsNames.Add("libpq.lib");
		// publicAdditionalLibsNames.Add("libssl.lib");
		publicAdditionalLibsNames.Add("libxml2.lib");
		publicAdditionalLibsNames.Add("lz4.lib");
		publicAdditionalLibsNames.Add("lzma.lib");
		publicAdditionalLibsNames.Add("netcdf.lib");
		publicAdditionalLibsNames.Add("openjp2.lib");
		publicAdditionalLibsNames.Add("pcre2-8.lib");
		publicAdditionalLibsNames.Add("pcre2-16.lib");
		publicAdditionalLibsNames.Add("pcre2-32.lib");
		publicAdditionalLibsNames.Add("pcre2-posix.lib");
		publicAdditionalLibsNames.Add("proj.lib");
		publicAdditionalLibsNames.Add("qhull_r.lib");
		publicAdditionalLibsNames.Add("qhullcpp.lib");
		publicAdditionalLibsNames.Add("spatialite.lib");
		publicAdditionalLibsNames.Add("sqlite3.lib");
		publicAdditionalLibsNames.Add("szip.lib");
		publicAdditionalLibsNames.Add("tiff.lib");
		publicAdditionalLibsNames.Add("turbojpeg.lib");
		publicAdditionalLibsNames.Add("webp.lib");
		publicAdditionalLibsNames.Add("webpdecoder.lib");
		publicAdditionalLibsNames.Add("webpmux.lib");
		// publicAdditionalLibsNames.Add("zlib.lib");
		publicAdditionalLibsNames.Add("zstd.lib");
		
		string LibFolder = Path.Combine(ModuleDirectory, "Lib", "Win64");

		foreach (string publicAdditionalLibsName in publicAdditionalLibsNames)
		{
			string libPath = Path.Combine(LibFolder, publicAdditionalLibsName);
			if (!File.Exists(libPath))
			{
				string err = $"Library '{libPath}' not found.";
				System.Console.WriteLine(err);
				throw new BuildException(err);
			}
			PublicAdditionalLibraries.Add(libPath);
		}
		
		// Dlls
		List<string> runtimeModuleNames = new List<string>();
		runtimeModuleNames.Add("gdal.dll");
		runtimeModuleNames.Add("charset-1.dll");
		runtimeModuleNames.Add("freexl-1.dll");
		runtimeModuleNames.Add("geos.dll");
		runtimeModuleNames.Add("geos_c.dll");
		runtimeModuleNames.Add("geotiff.dll");
		runtimeModuleNames.Add("gif.dll");
		runtimeModuleNames.Add("hdf5.dll");
		runtimeModuleNames.Add("hdf5_hl.dll");
		runtimeModuleNames.Add("hdf5_cpp.dll");
		runtimeModuleNames.Add("hdf5_hl_cpp.dll");
		runtimeModuleNames.Add("iconv-2.dll");
		runtimeModuleNames.Add("jpeg62.dll");
		runtimeModuleNames.Add("turbojpeg.dll");
		runtimeModuleNames.Add("json-c.dll");
		// runtimeModuleNames.Add("libcrypto-3-x64.dll");
		runtimeModuleNames.Add("libcurl.dll");
		runtimeModuleNames.Add("libexpat.dll");
		runtimeModuleNames.Add("liblzma.dll");
		// runtimeModuleNames.Add("libpng16.dll");
		// runtimeModuleNames.Add("libssl-3-x64.dll");
		// runtimeModuleNames.Add("legacy.dll");
		runtimeModuleNames.Add("libxml2.dll");
		runtimeModuleNames.Add("libecpg.dll");
		runtimeModuleNames.Add("libecpg_compat.dll");
		runtimeModuleNames.Add("libpgtypes.dll");
		runtimeModuleNames.Add("libpq.dll");
		runtimeModuleNames.Add("lz4.dll");
		runtimeModuleNames.Add("netcdf.dll");
		runtimeModuleNames.Add("openjp2.dll");
		runtimeModuleNames.Add("pcre2-8.dll");
		runtimeModuleNames.Add("pcre2-16.dll");
		runtimeModuleNames.Add("pcre2-32.dll");
		runtimeModuleNames.Add("pcre2-posix.dll");
		runtimeModuleNames.Add("proj.dll");
		runtimeModuleNames.Add("qhull_r.dll");
		runtimeModuleNames.Add("spatialite.dll");
		runtimeModuleNames.Add("sqlite3.dll");
		runtimeModuleNames.Add("tiff.dll");
		runtimeModuleNames.Add("webp.dll");
		runtimeModuleNames.Add("webpmux.dll");
		runtimeModuleNames.Add("webpdecoder.dll");
		runtimeModuleNames.Add("webpdemux.dll");
		// runtimeModuleNames.Add("zlib1.dll");
		runtimeModuleNames.Add("zstd.dll");
		runtimeModuleNames.Add("szip.dll");

		string binFolder = Path.Combine(PluginDirectory, "Binaries", "ThirdParty", "Win64");

		foreach (string runtimeModuleName in runtimeModuleNames)
		{
			string modulePath = Path.Combine(binFolder, runtimeModuleName);
			if (!File.Exists(modulePath))
			{
				string err = $"Module '{modulePath}' not found.";
				System.Console.WriteLine(err);
				throw new BuildException(err);
			}
			RuntimeDependencies.Add(Path.Combine(binFolder, runtimeModuleName));
		}
		
		// Delay load GDAL dll
		PublicDelayLoadDLLs.Add("gdal.dll");

		// Stage GDAL data files
		RuntimeDependencies.Add(Path.Combine(binFolder, "gdal/*"), StagedFileType.SystemNonUFS);
		// Stage Proj data files
		RuntimeDependencies.Add(Path.Combine(binFolder, "proj/*"), StagedFileType.SystemNonUFS);
	}
}

Commented lines are the modules already existing in the engine (as said above).

Everythings works find in the editor but when i compile and launch the app, I got a fatal error telling me that the dll that are not delay loaded (all dlls except gdal.dll) are not found.
image

I assume that its expected as windows doesn’t know these dlls. So do i need to DelayLoad all dlls but then i need to use GetDllHandle on all dlls before GetDllHandle on “gdal.dll” ?

Any ideas or examples to make this work ?

Corentin

Change

RuntimeDependencies.Add(Path.Combine(binFolder, runtimeModuleName));

with

RuntimeDependencies.Add("$(BinaryOutputDir)/" + runtimeModuleName, Path.Combine(binFolder, runtimeModuleName), StagedFileType.SystemNonUFS);

That way, the DLLs will be copied inside the same folder as your app’s exe during packaging and Windows will find them. You can also delay load them if you want after that.