,Hey all, I’m trying to load a c++ dll that references a C#.net library, and whenever I try to use the function it gives me the following:
An unhandled exception of type ‘System.IO.FileNotFoundException’ occurred in Unknown Module.
Additional information: Could not load file or assembly ‘Publics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxx’ or one of its dependencies. The system cannot find the file specified.
It works when I add Publics.dll directly to the Ue4Editor.exe folder, with symbols and everything. But everything I’ve tried to add to the path, or load manually, has failed.
This is my PluginModule.cpp file:
void PluginModule::StartupModule()
{
//Search project plugins folder for Dll
FString dllName = "ClassLibrary.dll"; // Going through this same process with Publics.dll doesn't work
if (SearchForDllPath(FPaths::GamePluginsDir(), dllName))
{
// Call the test function in the third party library that opens a message box
std::string val = ExampleCSharp(); // <-- Fails here
MessageBox(NULL, UTF8_TO_TCHAR(val.c_str()), NULL, NULL);
}
else if (SearchForDllPath(FPaths::EnginePluginsDir(), dllName)) //Failed in project dir, try engine plugins dir
{
}
else
{
//Stop loading - plugin required DLL to load successfully
checkf(false, TEXT("Failed to load dll"));
}
}
bool PluginModule::SearchForDllPath(FString _searchBase, FString _dllName)
{
//Search Plugins folder for an instance of Dll.dll, and add to platform search path
TArray<FString> directoriesToSkip;
IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
FLocalTimestampDirectoryVisitor Visitor(PlatformFile, directoriesToSkip, directoriesToSkip, false);
PlatformFile.IterateDirectory(*_searchBase, Visitor);
for (TMap<FString, FDateTime>::TIterator TimestampIt(Visitor.FileTimes); TimestampIt; ++TimestampIt)
{
const FString file = TimestampIt.Key();
const FString filePath = FPaths::GetPath(file);
const FString fileName = FPaths::GetCleanFilename(file);
if (fileName.Compare(_dllName) == 0)
{
FPlatformProcess::AddDllDirectory(*filePath); // only load dll when needed for use. Broken with 4.11.
FPlatformProcess::GetDllHandle(*file); // auto-load dll with plugin - needed as 4.11 breaks above line.
return true;
}
}
return false;
}
This is ClassLibrary.cpp, which generates ClassLibrary.dll:
#include "Stdafx.h"
#pragma once
#include <string>
#include <iostream>
#include "msclr\marshal_cppstd.h"
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT std::string ExampleCSharp()
{
msclr::interop::marshal_context context;
std::string ret = context.marshal_as<std::string>(Publics::Class1::Run());
return ret;
}
This is ClassLibrary.h, which references it:
#include <string>
#define DLLIMPORT __declspec(dllimport)
DLLIMPORT std::string ExampleCSharp();
This is my C# file, Class1.cs, which is a part of Publics.dll:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Publics
{
public static class Class1
{
public static string Run()
{
return "Hello From C# Land!";
}
}
}
Here is my plugin.build.cs file:
using System.IO;
using UnrealBuildTool;
public class nXhumanPluginLibrary : ModuleRules
{
public nXhumanPluginLibrary(TargetInfo Target)
{
Type = ModuleType.External;
if (Target.Platform == UnrealTargetPlatform.Win64)
{
//RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(ModuleDirectory, "x64", "Release", "Publics.dll"))); Doesn't work
// Add the import library
PublicLibraryPaths.Add(Path.Combine(ModuleDirectory, "x64", "Release"));
PublicAdditionalLibraries.Add("ClassLibrary.lib");
//PublicAdditionalLibraries.Add("Publics.dll"); Doesn't work
// Delay-load the DLL, so we can load it from the right place first
PublicDelayLoadDLLs.Add("ClassLibrary.dll");
//PublicDelayLoadDLLs.Add("Publics.dll"); Doesn't work
//PrivateAssemblyReferences.Add(Path.Combine(ModuleDirectory, "x64", "Release", "Publics.dll")); Doesn't Work
}
}
}