版权声明:本文为CSDN博主「蓬 蒿 人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
在 UE4 中使用 静态链接库 和 动态链接库 与普通程序中使用差不多,只是要在编译文件中设置库文件路径。下面创建一个 第三人称 模板的 C++ 工程 ThirdPerson ,使用 这篇文章中的静态链接库和动态链接库。
一、静态链接库
在工程目录新建一个文件夹 ThirdParty(与 Content 目录同一级),将 CaptureScreen.h 和CaptureScreen.lib 复制到这个文件夹,接下来要在编译文件 .build.cs 文件中将这个目录添加到包含目录,使 UE4 能搜索到头文件(如果没有添加包含目录,头文件的路径就是 ../../ThirdParty/CaptureScreen.h ),然后将 CaptureScreen.lib 添加到依赖库列表中。
ThirdPerson.build.cs 文件大致如下
ThirdPerson.Build.cs
using UnrealBuildTool;
using System.IO;
public class ThirdPerson : ModuleRules
{
public
ThirdPerson(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]{"Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "ImageWrapper"});
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath)); ///< *
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "CaptureScreen.lib")); ///< *
}
private
string ThirdPartyPath ///< *
{
get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty/")); }
}
}
在 AThirdPersonGameMode 类中实现一个蓝图可调用的函数 TestCapture 来调用静态库中的函数,在游戏运行期间都可以调用来获取屏幕截图,为了方便这里就在 StartPlay 中调用 TestCapture。.h 和 .cpp 代码如下
ThirdPersonGameMode.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "ThirdPersonGameMode.generated.h"
UCLASS(minimalapi)
class AThirdPersonGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AThirdPersonGameMode();
void StartPlay();
void EndPlay(const EEndPlayReason::Type EndPlayReason);
UFUNCTION(BlueprintCallable)
void TestCapture(int x,int y,int width,int height); ///< *
};
ThirdPersonGameMode.cpp
#include "ThirdPersonGameMode.h"
#include "ThirdPersonCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include"IImageWrapperModule.h"
#include"ModuleManager.h"
#include"IImageWrapper.h"
#include"Misc/FileHelper.h"
#include"CaptureScreen.h" ///< 包含静态库的头文件
AThirdPersonGameMode::AThirdPersonGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
}
bool OnCaptureData(const char* InData, int InWidth, int InHeight, int InBytesPerColor)
{
/*FString ScreenShotName = FPaths::ProjectSavedDir() + TEXT("ScreenShot.png");
TArray<FColor> colors;
colors.AddZeroed(InHeight*InWidth);
for (int i = 0; i < InHeight; i++)
{
for (int j = 0; j < InWidth; j++)
{
int DestIndex = i * InWidth + j;
//(InHeight-i-1):BMP数据是从左下角到右上角的顺序,也就是上下颠倒的,所以要倒回来
int SrcIndex =((InHeight -i-1) * InWidth + j) * InBytesPerColor;
colors[DestIndex].B = InData[SrcIndex];
colors[DestIndex].G = InData[SrcIndex+1];
colors[DestIndex].R = InData[SrcIndex+2];
colors[DestIndex].A = 255;
}
}
IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
if (ImageWrapper->SetRaw(colors.GetData(), colors.Num()*sizeof(FColor),InWidth, InHeight, ERGBFormat::BGRA, 8))
{
FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *ScreenShotName);
}*/
return true;
}
void AThirdPersonGameMode::StartPlay()
{
Super::StartPlay();
TestCapture(0,0,0,0); ///< *
}
void AThirdPersonGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
/// @note 调用静态库中的函数
void AThirdPersonGameMode::TestCapture(int x, int y, int width, int height)
{
RunCapture(x, y, width, height, OnCaptureData);
}
二、动态链接库
动态链接库同时需要将 CaptureScreen.dll 文件放到 ThirdParty 目录,使用动态链接库有两种方式,
- 一种是通过 .h 和 .lib 文件直接调用,
- 一种是只用 dll 文件通过查找函数地址来使用。
1. 通过 .lib 文件使用动态链接库
ThirdPerson.build.cs 文件内容跟上面的差不多,只是要将 dll 文件添加到 延迟加载列表 PublicDelayLoadDLLs 中,如果不添加就会在引擎启动的时候加载,导致出错(不知道还有没有其他的解决办法)。
ThirdPerson.Build.cs
using UnrealBuildTool;
using System.IO;
public class ThirdPerson : ModuleRules
{
private
string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty/")); }
}
public
ThirdPerson(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]{"Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "ImageWrapper"});
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath)); ///< *
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "CaptureScreen.lib")); ///< *
PublicDelayLoadDLLs.Add("CaptureScreen.dll"); ///*
}
}
在使用 dll 中的函数之前(本例在 StartPlay 中)要通过调用 PushDllDirectory 函数将 Thirdparty 目录加入到 dll 搜索路径,否则找不到 dll 文件(如果将 dll 文件放到工程目录 /Binaries/Win64 下可以不调用)。
ThirdPersonGameMode.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "ThirdPersonGameMode.generated.h"
UCLASS(minimalapi)
class AThirdPersonGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AThirdPersonGameMode();
void StartPlay();
void EndPlay(const EEndPlayReason::Type EndPlayReason);
UFUNCTION(BlueprintCallable)
void TestCapture(int x,int y,int width,int height);
};
ThirdPersonGameMode.cpp
#include "ThirdPersonGameMode.h"
#include "ThirdPersonCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include"IImageWrapperModule.h"
#include"ModuleManager.h"
#include"IImageWrapper.h"
#include"Misc/FileHelper.h"
#include"CaptureScreen.h" ///< 包含头文件
AThirdPersonGameMode::AThirdPersonGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
}
bool OnCaptureData(const char* InData, int InWidth, int InHeight, int InBytesPerColor)
{
/*FString ScreenShotName = FPaths::ProjectSavedDir() + TEXT("ScreenShot.png");
TArray<FColor> colors;
colors.AddZeroed(InHeight*InWidth);
for (int i = 0; i < InHeight; i++)
{
for (int j = 0; j < InWidth; j++)
{
int DestIndex = i * InWidth + j;
// (InHeight-i-1):BMP数据是从左下角到右上角的顺序,也就是上下颠倒的,所以要倒回来
int SrcIndex =((InHeight -i-1) * InWidth + j) * InBytesPerColor;
colors[DestIndex].B = InData[SrcIndex];
colors[DestIndex].G = InData[SrcIndex+1];
colors[DestIndex].R = InData[SrcIndex+2];
colors[DestIndex].A = 255;
}
}
IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
if (ImageWrapper->SetRaw(colors.GetData(), colors.Num()*sizeof(FColor),InWidth, InHeight, ERGBFormat::BGRA, 8))
{
FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *ScreenShotName);
}*/
return true;
}
void AThirdPersonGameMode::StartPlay()
{
Super::StartPlay();
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("ThirdParty/")));///< 将 dll 存放目录加入搜索路径
TestCapture(0,0,0,0); ///< *
}
void AThirdPersonGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
/// @note 调用函数
void AThirdPersonGameMode::TestCapture(int x, int y, int width, int height)
{
RunCapture(x, y, width, height, OnCaptureData);
}
2. 直接使用 dll 文件
直接使用 dll 文件来调用库中的函数只需要一个 dll 文件,.build.cs 文件也不用改,可直接用 GetDllExport 通过函数名称从 dll 中取得需要调用的函数。
ThirdPersonGameMode.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "ThirdPersonGameMode.generated.h"
UCLASS(minimalapi)
class AThirdPersonGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AThirdPersonGameMode();
void StartPlay();
void EndPlay(const EEndPlayReason::Type EndPlayReason);
UFUNCTION(BlueprintCallable)
void TestCapture(int x,int y,int width,int height);
void* CaptureScreenHandle=nullptr;
};
ThirdPersonGameMode.cpp
#include "ThirdPersonGameMode.h"
#include "ThirdPersonCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include"IImageWrapperModule.h"
#include"ModuleManager.h"
#include"IImageWrapper.h"
#include"Misc/FileHelper.h"
AThirdPersonGameMode::AThirdPersonGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
}
bool OnCaptureData(const char* InData, int InWidth, int InHeight, int InBytesPerColor)
{
/*FString ScreenShotName = FPaths::ProjectSavedDir() + TEXT("ScreenShot.png");
TArray<FColor> colors;
colors.AddZeroed(InHeight*InWidth);
for (int i = 0; i < InHeight; i++)
{
for (int j = 0; j < InWidth; j++)
{
int DestIndex = i * InWidth + j;
//(InHeight-i-1):BMP数据是从左下角到右上角的顺序,也就是上下颠倒的,所以要倒回来
int SrcIndex =((InHeight -i-1) * InWidth + j) * InBytesPerColor;
colors[DestIndex].B = InData[SrcIndex];
colors[DestIndex].G = InData[SrcIndex+1];
colors[DestIndex].R = InData[SrcIndex+2];
colors[DestIndex].A = 255;
}
}
IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
if (ImageWrapper->SetRaw(colors.GetData(), colors.Num()*sizeof(FColor),InWidth, InHeight, ERGBFormat::BGRA, 8))
{
FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *ScreenShotName);
}*/
return true;
}
void AThirdPersonGameMode::StartPlay()
{
Super::StartPlay();
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("ThirdParty/")));///< 将 dll 存放目录加入搜索路径
CaptureScreenHandle = FPlatformProcess::GetDllHandle(TEXT("CaptureScreen.dll"));///< 或者全路径 FPaths::ProjectDir()/TEXT("ThirdParty/CaptureScreen.dll")
TestCapture(0,0,0,0); ///< *
}
void AThirdPersonGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (CaptureScreenHandle)
{
FPlatformProcess::FreeDllHandle(CaptureScreenHandle);
CaptureScreenHandle = nullptr;
}
Super::EndPlay(EndPlayReason);
}
/// @note *
typedef bool(*OnCaptureComplete)(const char*, int, int, int);
typedef bool(*RunCaptureProc)(int, int, int, int, OnCaptureComplete);
/// @note 调用动态库函数
void AThirdPersonGameMode::TestCapture(int x, int y, int width, int height)
{
if (!CaptureScreenHandle)
{
return;
}
RunCaptureProc RunCapture = (RunCaptureProc)FPlatformProcess::GetDllExport(CaptureScreenHandle, TEXT("RunCapture"));
if (RunCapture)
{
RunCapture(x, y, width, height, OnCaptureData);
}
}
如果 dll 文件不依赖其他 dll 文件,GetDllHandle 可传入 dll 文件的完整路径而不需要 PushDllDirectory,但是如果 dll 还依赖于其他 dll 文件并且也在 Thirdparty 目录下,就必须调用PushDllDirectory,否则找不到依赖的 dll 文件。