Hi,
We have a module that depends on MATLAB libraries for certain data types and methods. These libraries are specified in the module’s `Build.cs` file using `PublicAdditionalLibraries.AddRange(…)`. When the libraries cannot be found (since they are located in the MATLAB installation directory, which is not on the engine’s search path by default), the module fails to load unless the project is launched from within the MATLAB process.
We are looking for a user-friendly solution that would allow users to open the project outside of MATLAB/Simulink—without requiring them to modify the system path or use a custom launcher script. Ideally, we’d like to prompt users for their MATLAB installation path in order to find the libraries, save it for future use, or implement a similar intuitive workflow.
Additionally, if the required libraries are not found (i.e., MATLAB is not installed), is there a way to display a dialog box informing users that they need to disable the plugin in order to launch the project?
Any guidance or recommended approaches for handling these scenarios within the Unreal Engine pipeline would be greatly appreciated.
Thanks,
Suhair
Hi,
You can do this by delay loading the DLLs and manually load them at runtime using FPlatformProcess::GetDLLHandle(), assuming nothing call the library before you can load it. Then you can use the IFileManager to check if the DLLs exist before loading tem and if they are not present, you can show a message box to the user to tell them to install. If you want to be flexible, you can add a CVar user can set in their .ini file to set the path to the libraries.
I made a demo project (Demo.zip attached) where I made a simple Windows DLL (MyCustomLib2.dll). I made a plugin (MyCommonPlugin) that will delay load the DLL and load it dynamically in the module startup. I added code to show how you can check if a DLL is present and how to show a MessageBox. Here the important files to look.
MyCommonPlugin\Source\MyCommonPlugin\MyCommonPlugin.Build.cs
public MyCommonPlugin(ReadOnlyTargetRules Target) : base(Target)
{
string MyCustomLibRoot = "C:/Users/patrick.laflamme/source/repos/MyCustomLib2/";
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
"MyCommonPlugin/Public"
});
PrivateIncludePaths.AddRange(
new string[] {
MyCustomLibRoot + "MyCustomLib2", // C:/Users/patrick.laflamme/source/repos/MyCustomLib2/MyCustomLib2
});
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Projects",
});
PublicAdditionalLibraries.Add(MyCustomLibRoot + "x64/Release/MyCustomLib2.lib");
RuntimeDependencies.Add(MyCustomLibRoot + "x64/Release/MyCustomLib2.dll"); // C:/Users/patrick.laflamme/source/repos/MyCustomLib2/MyCustomLib2/x64/Release/MyCustomLib2.dll
PublicDelayLoadDLLs.Add("MyCustomLib2.dll");
PublicDefinitions.Add("MYCUSTOMLIB2_DLL_PATHNAME=\"" + MyCustomLibRoot + "x64/Release/MyCustomLib2.dll\"");
}
MyCommonPlugin\Source\MyCommonPlugin\Private\MyCommonPlugin.cpp
#include "MyCommonPlugin.h"
#include "Interfaces/IPluginManager.h"
#include "HAL/PlatformProcess.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformMisc.h"
#include "MyCustomLib2.h"
static TAutoConsoleVariable<FString> CVarMyCustomLib2DllPathname(
TEXT("myCustomlib2.DllPathname"),
TEXT(""),
TEXT("Path to my lib."));
void FMyCommonPluginModule::StartupModule()
{
FString MyCustomLib2DllPathname = MYCUSTOMLIB2_DLL_PATHNAME; //"C:\\Users\\patrick.laflamme\\source\\repos\\MyCustomLib2\\x64\\Release\\MyCustomLib2.dll";
if (!IFileManager::Get().FileExists(*MyCustomLib2DllPathname))
{
// Read a CVar? See \Engine\Plugins\Developer\RenderDocPlugin\Source\RenderDocPlugin\Private\RenderDocPluginLoader.cpp for an example.
MyCustomLib2DllPathname = CVarMyCustomLib2DllPathname.GetValueOnGameThread();
}
if (!IFileManager::Get().FileExists(*MyCustomLib2DllPathname))
{
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, TEXT("Please install the library or set the CVar myCustomlib2.DllPathname"), TEXT("Missing library"));
}
else
{
if (void* Handle = FPlatformProcess::GetDllHandle(*MyCustomLib2DllPathname))
{
GLog->Logf(TEXT("======================= Calling the lib: %d"), fnMyCustomLib2());
}
else
{
// FATAL LOG.
}
}
}
That shows the principle, you can polish it to your liking. You can also look around in the engine for ‘PublicDelayLoadDLLs’ or ‘FPlatformProcess::GetDllHandle’ if you want other examples.
Regards,
Patrick