UE4中引用第三方库和一般C++项目是有区别的。下面主要介绍lib静态库和dll动态库的引用: Demo调试工具:UE4.15.3 、VS2015
首先在UE4中新建一个空的C++项目,命名为“JNI_Test”,新建一个C++类,继承自BlueprintFunctionLibrary,命名为“LinkDllBFL”,之后在这定义静态全局函数实现第三方库函数的调用。在JNI_Test项目目录下新建两个文件夹Resources和ThirdPart用于存放后文中的两种第三方库。
UE4中lib静态库的引用需要依赖UBT(Unreal Building System)系统,所以需要在Build.cs中实现。
在VS中创建新Win32项目,命名“LibTest”,程序类型为静态连接库。在解决方案中添加名为“MyLib”的类: Mylib.h
#pragma once //通过半径计算面积 float getCircleArea(float radius);Mylib.cpp
#include "stdafx.h" #include "MyLib.h" float getCircleArea(float radius) { return 3.14159265 * (radius * radius); }选择x64编译生成解决方案,在项目文件夹中找到x64下的“LibTest.lib”和”MyLib.h”,此处将这两个文件复制到UE4项目“JNI_Test”的“JNI_Test/ThirdPart/x64”目录中。
接下来,打开项目C++代码,开始修改Build.cs:
// Fill out your copyright notice in the Description page of Project Settings. using UnrealBuildTool; using System; using System.IO; public class JNI_Test : ModuleRules { private string ThirdPartPath { //通过get方法获得ModuleDirectory上两级的ThirdPart目录。 //ModuleDirectory指的是Build.cs所在的目录 get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdPart")); } } //加载lib(此处判断了平台信息,预留了win32的接口) private bool LoadThirdPartLib(TargetInfo Target) { if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32)) { string platformStr = Target.Platform == UnrealTargetPlatform.Win64 ? "x64" : "x86"; //得到lib地址 string lib_path = Path.Combine(ThirdPartPath, platformStr, "LibTest.lib"); //添加lib库到includepaths PublicAdditionalLibraries.Add(lib_path); PrivateIncludePaths.Add(Path.Combine(ThirdPartPath, platformStr)); PublicIncludePaths.Add(Path.Combine(ThirdPartPath, platformStr)); return true; } return false; } public JNI_Test(TargetInfo Target) { LoadThirdPartLib(Target); PublicIncludePaths.AddRange(new string[] { "JNI_Test/Public" }); PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); PrivateDependencyModuleNames.AddRange(new string[] { }); // Uncomment if you are using Slate UI // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); // Uncomment if you are using online features // PrivateDependencyModuleNames.Add("OnlineSubsystem"); // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true } }修改完成之后静态库的引入就完成了,是不是很简单。接下来在需要使用lib库中函数的头文件中添加#include “MyLib.h”即可调用lib库中的getCircleArea函数了。
LinkDllBFL.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "MyLib.h" #include "LinkDllBFL.generated.h" /** * */ UCLASS() class JNI_TEST_API ULinkDllBFL : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "Lib") static float circleArea(float radius); };LinkDllBFL.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "JNI_Test.h" #include "LinkDllBFL.h" //调用lib库中getCircleArea函数 float ULinkDllBFL::circleArea(float radius) { return getCircleArea(radius); }生成或者compile编译项目。
之后我们在UE4编辑器中创建一个JNI_TestGameModeBase的蓝图类“MyJNI_TestGameModeBase”,在MyJNI_TestGameModeBase中编辑如下: 然后点击Play运行项目,运行结果如下:
动态链接库dll的引用与静态链接库不同,不需要依赖UBT系统,直接在C++代码中动态引入即可。 步骤如下:
在VS中创建新Win32项目,命名“DllTest”,程序类型为dll动态连接库。在解决方案中添加名为“MyDllTest”的类: MyDllTest.h
#pragma once #define DLL_EXPORT __declspec(dllexport)//定义dll的函数导出接口 #ifdef __cplusplus extern "C" { #endif float DLL_EXPORT getCircleArea(float radius); #ifdef __cplusplus } #endifMyDllTest.cpp
#include "MyDllTest.h" float DLL_EXPORT getCircleArea(float radius) { return float(3.14159265 * (radius * radius)); }依然选择x64编译解决方案DllTest。在DllTest\x64\Debug 中找到生成的“DllTest.dll”文件,复制到UE4项目的JNI_Test\Resources 目录下。 之后开始在UE4项目的C++代码中修改:
LinkDllBFL.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "MyLib.h" #include "LinkDllBFL.generated.h" /** * */ UCLASS() class JNI_TEST_API ULinkDllBFL : public UBlueprintFunctionLibrary { GENERATED_BODY() public: //调用lib库中getCircleArea函数 UFUNCTION(BlueprintCallable, Category = "Lib") static float circleArea(float radius); UFUNCTION(BlueprintCallable, Category = "DLL") static bool importDLL(FString folder, FString name); UFUNCTION(BlueprintCallable, Category = "DLL") static bool importMethodGetCircleArea(); UFUNCTION(BlueprintCallable, Category = "DLL") static float getCircleAreaFromDll(float radius); UFUNCTION(BlueprintCallable, Category = "DLL") static void freeDLL(); };LinkDllBFL.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "JNI_Test.h" #include "LinkDllBFL.h" typedef float(*_getCircleArea)(float radius);//定义一个函数指针来存储dll中的getCircleArea函数原型 _getCircleArea m_getCircleAreaFromDll; void *dllHandle; //加载DLL bool ULinkDllBFL::importDLL(FString folder, FString name) { FString filePath = *FPaths::GameDir() + folder + "/" + name; if (FPaths::FileExists(filePath)) { dllHandle = FPlatformProcess::GetDllHandle(*filePath);//得到dll句柄 if (dllHandle != NULL) { return true; } } return false; } //从DLL中得到函数getCircleArea bool ULinkDllBFL::importMethodGetCircleArea() { if (dllHandle != NULL) { m_getCircleAreaFromDll = NULL; FString procName = "getCircleArea"; m_getCircleAreaFromDll = (_getCircleArea)FPlatformProcess::GetDllExport(dllHandle, *procName); if (m_getCircleAreaFromDll != NULL) { return true; } } return false; } //调用从DLL中传入的getCircleArea函数 float ULinkDllBFL::getCircleAreaFromDll(float radius) { if (m_getCircleAreaFromDll != NULL) { float out = float(m_getCircleAreaFromDll(radius));//调用dll函数 return out; } return -32202.0f;//返回错误 } //卸载DLL void ULinkDllBFL::freeDLL() { if (dllHandle != NULL) { m_getCircleAreaFromDll = NULL; FPlatformProcess::FreeDllHandle(dllHandle); dllHandle = NULL; } } float ULinkDllBFL::circleArea(float radius) { return getCircleArea(radius); }此处我们在LinkDllBFL中实现了4个静态全局函数,分别实现了加载dll、得到dll函数、调用dll函数、卸载dll的功能,之后我们还是来到UE4编辑器中用蓝图实现函数的调用。
编译保存之后,Play!! 得到了和上文lib相同的结果:
参考文章: https://wiki.unrealengine.com/Linking_Static_Libraries_Using_The_Build_System https://wiki.unrealengine.com/Linking_Dlls