概述
UE4的第三方库,大家都建议使用插件进行整合,那么我也尝试一下插件整合。
首先先写一个C++的动态库:
在AddSdk.h的头文件里面,定义一个函数:
__declspec(dllimport) int Test_Add(int a, int b);
实现函数如下:
__declspec(dllexport) int Test_Add(int a, int b)
{
return a + b;
}
编译之后,会生成一个动态库
然后在UE4里面添加一个空的插件SimplePlug
在Source文件夹下面新建一个文件夹ThirdParty
在include里面放置头文件的定义,在lib里面放置lib文件和dll文件
然后需要在SimplePlug.Build.cs里面设置一下
整个代码如下:
// Copyright Epic Games, Inc. All Rights Reserved.
using System.IO;
using UnrealBuildTool;
public class SimplePlug : ModuleRules
{
string ThirdPartyPath
{
get
{
return Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty/"));
}
}
public SimplePlug(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",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
string includePath = Path.Combine(ThirdPartyPath, "include");
PublicIncludePaths.Add(includePath);
string LibPath = Path.Combine(ThirdPartyPath, "lib");
PublicAdditionalLibraries.Add(Path.Combine(LibPath,"X64", "AddDll.lib"));
PublicDelayLoadDLLs.Add(Path.Combine(LibPath, "X64", "AddDll.dll"));
}
}
上述代码主要实现头文件的引入,lib文件的依赖 以及动态库的依赖。
最后新建一个AMyActor
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyActor.h"
#include "AddSdk.h"
// Sets default values
AMyActor::AMyActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogTemp, Log, TEXT("Your message =%i"),Test_Add(1,2));
}
// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
最后发现效果不错:符合预期要求
*********************************************2020-07-25*************************************
上面的操作存在两个问题:
1、打包之后,无法调用动态库
2、需要手动拷贝动态库到程序当前路径下。
为了解决这两个问题,有研究了一下
增加拷贝函数,实现把动态库拷贝到需要运行的路径下:
输入参数FIlepath 为动态库的全路径
private void CopyDllAndLibToProjectBinaries(string Filepath, ReadOnlyTargetRules Target)
{
string BinariesDirectory = Path.Combine(ModuleDirectory,"../../", "Binaries/ThirdParty", Target.Platform.ToString());
string Filename = Path.GetFileName(Filepath);
if (!Directory.Exists(BinariesDirectory))
{
Directory.CreateDirectory(BinariesDirectory);
}
File.Copy(Filepath, Path.Combine(BinariesDirectory, Filename), true);
RuntimeDependencies.Add(Path.Combine(BinariesDirectory, Filename));
}
另外,把动态库的引入修改为延迟加载,把加载放置到启动module里面,这样可以选择合适的路径来加载动态库
string includePath = Path.Combine(ThirdPartyPath, "include");
PublicIncludePaths.Add(includePath);
string LibPath = Path.Combine(ThirdPartyPath, "lib");
PublicAdditionalLibraries.Add(Path.Combine(LibPath,"X64", "AddDll.lib"));
PublicDelayLoadDLLs.Add("AddDll.dll");
CopyDllAndLibToProjectBinaries(Path.Combine(ThirdPartyPath, "lib", "X64", "AddDll.dll"), Target);
加载和释放动态库
// Copyright Epic Games, Inc. All Rights Reserved.
#include "SimplePlug.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#define LOCTEXT_NAMESPACE "FSimplePlugModule"
void FSimplePlugModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// Get the base directory of this plugin
FString BaseDir = IPluginManager::Get().FindPlugin("SimplePlug")->GetBaseDir();
// Add on the relative location of the third party dll and load it
FString LibraryPath;
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/Win64/AddDll.dll"));
ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;
if (ExampleLibraryHandle)
{
// Call the test function in the third party library that opens a message box
}
else
{
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));
}
}
void FSimplePlugModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
// Free the dll handle
FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);
ExampleLibraryHandle = nullptr;
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FSimplePlugModule, SimplePlug)
最后发现一直无法编译通过,需要在下面增加“Projects”
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
"Projects"
}
);
至此,可以实现动态库的自动拷贝,以及实现加载不同路径的动态库,以及打包之后可以正常运行。
***********************************20200822******************************
今天写了一个UE4集成Mqtt的库,反复阅读了上面写的文章,又有了新的体会。
这里写点心得:
1、我们写的插件可以直接拷贝到其他工程,都是可以直接运行的。只需要重新生成一下vs工程即可。
2、我们这里插件采用懒加载,避免启动蓝图的时候直接失败。(遇到这个问题查了好久)
懒加载如下:在插件的xxxx.Build.cs文件里面
PublicDelayLoadDLLs.Add("PlugMqttLibrary.dll");
3、我们加载动态库直接在启动module的时候加载,这里我贴一下我的示例代码。这里要特别注意,我们需要编辑器调用的dll与运行的时候调用的dll不一样,吃过这个亏。通过宏开关来判断 WITH_EDITOR
// Copyright Epic Games, Inc. All Rights Reserved.
#include "PlugMqtt.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#define LOCTEXT_NAMESPACE "FPlugMqttModule"
void FPlugMqttModule::StartupModule()
{
pahomqtt3aLibraryHandle = nullptr;
pahomqttpp3LibraryHandle = nullptr;
PlugMqttLibraryHandle = nullptr;
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// Get the base directory of this plugin
FString BaseDir = IPluginManager::Get().FindPlugin("PlugMqtt")->GetBaseDir();
FString pahomqtt3aLibraryPath;
FString pahomqttpp3LibraryPath;
FString PlugMqttLibraryPath;
#if WITH_EDITOR // WITH_EDITOR
// Add on the relative location of the third party dll and load it
pahomqtt3aLibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/PlugMqttLibrary/lib/paho-mqtt3a.dll"));
pahomqttpp3LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/PlugMqttLibrary/lib/paho-mqttpp3.dll"));
PlugMqttLibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/PlugMqttLibrary/x64/Debug/PlugMqttLibrary.dll"));
#else
pahomqtt3aLibraryPath = FPaths::Combine(*BaseDir, TEXT("../../Binaries/ThirdParty/Win64/paho-mqtt3a.dll"));
pahomqttpp3LibraryPath = FPaths::Combine(*BaseDir, TEXT("../../Binaries/ThirdParty/Win64/paho-mqttpp3.dll"));
PlugMqttLibraryPath = FPaths::Combine(*BaseDir, TEXT("../../Binaries/ThirdParty/Win64/PlugMqttLibrary.dll"));
#endif
pahomqtt3aLibraryHandle = !pahomqtt3aLibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*pahomqtt3aLibraryPath) : nullptr;
pahomqttpp3LibraryHandle = !pahomqttpp3LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*pahomqttpp3LibraryPath) : nullptr;
PlugMqttLibraryHandle = !PlugMqttLibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*PlugMqttLibraryPath) : nullptr;
if (nullptr == pahomqtt3aLibraryHandle)
{
UE_LOG(LogTemp, Error, TEXT("GetDllHandle = %s"), *pahomqtt3aLibraryPath);
}
if (nullptr == pahomqttpp3LibraryHandle)
{
UE_LOG(LogTemp, Error, TEXT("GetDllHandle = %s"), *pahomqttpp3LibraryPath);
}
if (nullptr == PlugMqttLibraryHandle)
{
UE_LOG(LogTemp, Error, TEXT("GetDllHandle = %s"), *PlugMqttLibraryPath);
}
}
void FPlugMqttModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
// Free the dll handle
if (nullptr == pahomqtt3aLibraryHandle)
{
FPlatformProcess::FreeDllHandle(pahomqtt3aLibraryHandle);
pahomqtt3aLibraryHandle = nullptr;
}
if (nullptr == pahomqttpp3LibraryHandle)
{
FPlatformProcess::FreeDllHandle(pahomqttpp3LibraryHandle);
pahomqtt3aLibraryHandle = nullptr;
}
if (nullptr == PlugMqttLibraryHandle)
{
FPlatformProcess::FreeDllHandle(PlugMqttLibraryHandle);
PlugMqttLibraryHandle = nullptr;
}
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FPlugMqttModule, PlugMqtt)
4、需要把动态库拷贝到运行加载的目录中去,这样才能加载。这里直接把整个build.cs文件贴上来。
// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.IO;
using UnrealBuildTool;
public class PlugMqtt : ModuleRules
{
private void CopyDllAndLibToProjectBinaries(string Filepath, ReadOnlyTargetRules Target)
{
string BinariesDirectory = Path.Combine(ModuleDirectory, "../../../../", "Binaries/ThirdParty", Target.Platform.ToString());
Console.WriteLine(BinariesDirectory);
string Filename = Path.GetFileName(Filepath);
if (!Directory.Exists(BinariesDirectory))
{
Directory.CreateDirectory(BinariesDirectory);
}
File.Copy(Filepath, Path.Combine(BinariesDirectory, Filename), true);
RuntimeDependencies.Add(Path.Combine(BinariesDirectory, Filename));
}
public PlugMqtt(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"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
string LibPath = Path.Combine(ModuleDirectory, "../ThirdParty/PlugMqttLibrary/x64/Debug/");
PublicAdditionalLibraries.Add(Path.Combine(LibPath, "PlugMqttLibrary.lib"));
PublicDelayLoadDLLs.Add("PlugMqttLibrary.dll");
CopyDllAndLibToProjectBinaries(Path.Combine(ModuleDirectory, "../ThirdParty/PlugMqttLibrary/", "x64", "Debug", "PlugMqttLibrary.dll"), Target);
CopyDllAndLibToProjectBinaries(Path.Combine(ModuleDirectory, "../ThirdParty/PlugMqttLibrary/lib", "paho-mqtt3a.dll"), Target);
CopyDllAndLibToProjectBinaries(Path.Combine(ModuleDirectory, "../ThirdParty/PlugMqttLibrary/lib", "paho-mqttpp3.dll"), Target);
}
}
5、如果要在插件里面编写UE4的对象,需要添加模块依赖,主要是CoreUObject和Engine 如下:
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"Projects"
// ... add other public dependencies that you statically link with here ...
}
);
最后
以上就是笨笨吐司为你收集整理的UE4之整合第三方库的全部内容,希望文章能够帮你解决UE4之整合第三方库所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复