前言 本文介绍一下UE4使用第三方库的简单用法, 即DLL
动态库和Lib
静态库的使用
我们用插件的形式封装起来, 便于以后移植到其他项目中去;
所以在开始之前先新建一个空或者蓝图库插件
导出动态/静态库 新建控制台应用程序ThirdPartyDLL
然后创建一个同名头文件,写入一下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #pragma once #define DLL_EXPORT __declspec(dllexport) #ifdef __cplusplus extern "C" { #endif int DLL_EXPORT GetMac (char * mac) ; #ifdef __cplusplus } #endif
因为要确保函数名称我们用C的方式编译即extern "C"
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 #pragma once #include "string.h" #include "ThirdPartyDLL.h" #include <windows.h> #include <wincon.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include <Nb30.h> #pragma comment(lib,"netapi32.lib" ) int GetMac (char * mac) { NCB ncb; typedef struct _ASTAT_ { ADAPTER_STATUS adapt; NAME_BUFFER NameBuff[30 ]; }ASTAT, *PASTAT; ASTAT Adapter; typedef struct _LANA_ENUM { UCHAR length; UCHAR lana[MAX_LANA]; }LANA_ENUM; LANA_ENUM lana_enum; UCHAR uRetCode; memset (&ncb, 0 , sizeof (ncb)); memset (&lana_enum, 0 , sizeof (lana_enum)); ncb.ncb_command = NCBENUM; ncb.ncb_buffer = (unsigned char *)&lana_enum; ncb.ncb_length = sizeof (LANA_ENUM); uRetCode = Netbios (&ncb); if (uRetCode != NRC_GOODRET) return uRetCode; for (int lana = 0 ; lana < lana_enum.length; lana++) { ncb.ncb_command = NCBRESET; ncb.ncb_lana_num = lana_enum.lana[lana]; uRetCode = Netbios (&ncb); if (uRetCode == NRC_GOODRET) break ; } if (uRetCode != NRC_GOODRET) return uRetCode; memset (&ncb, 0 , sizeof (ncb)); ncb.ncb_command = NCBASTAT; ncb.ncb_lana_num = lana_enum.lana[0 ]; strcpy ((char *)ncb.ncb_callname, "*" ); ncb.ncb_buffer = (unsigned char *)&Adapter; ncb.ncb_length = sizeof (Adapter); uRetCode = Netbios (&ncb); if (uRetCode != NRC_GOODRET) return uRetCode; sprintf (mac, "%02X-%02X-%02X-%02X-%02X-%02X" , Adapter.adapt.adapter_address[0 ], Adapter.adapt.adapter_address[1 ], Adapter.adapt.adapter_address[2 ], Adapter.adapt.adapter_address[3 ], Adapter.adapt.adapter_address[4 ], Adapter.adapt.adapter_address[5 ]); return 0 ; } int main () { char mac[200 ]; GetMac (mac); printf ("The Mac Address is : %s \n" , mac); system ("pause" ); return 0 ; }
上述内容目的是获取本地的mac
地址, 不用理会具体实现方法, 我们主要是拿来当作第三方库使用, 毕竟UE4现在自己的API没有可以拿到Mac
地址的;
设置模式为 Release
+x64
在vs中简单运行一下得到结果
运行正常, 然后是导出我们所需要的动态库
在项目属性里设置配置类型为DLL,如下
生成以后就得到了我们需要的DLL
文件
静态库只需要在项目配置里修改成Lib
,然后再生成一次即可
UE4封装函数库 静态方法 先到插件目录下,在source
同级目录下新建文件夹ThirdParty
,然后分别创建子文件夹DLL
,Include
,Lib
,如下
分别放入的文件为ThirdPartyDLL.dll
,ThirdPartyDLL.h
,ThirdPartyDLL.lib
然后来到我们的插件模块,找到*.build.cs
文件,添加必要路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private string ModulePath { get { return ModuleDirectory; } } private string ThirdPartyPath { get { return Path.GetFullPath (Path.Combine (ModulePath, "../../ThirdParty/" )); } } PublicIncludePaths.Add (Path.Combine (ThirdPartyPath, "Include" )); PublicAdditionalLibraries.Add (Path.Combine (ThirdPartyPath, "Lib" , "ThirdPartyDLL.lib" ));
这样我们就可以在自己的cpp中包含静态库的头文件了
找到/创建蓝图函数库
头文件下声明如下函数
1 2 UFUNCTION (BlueprintCallable, BlueprintPure ,Category = "Flib|DllHelper" , meta = (DisplayName = "GetMac" )) static FString GetMacFromLib () ;
然后实现
1 2 3 4 5 6 7 8 9 #include "ThirdPartyDLL.h" FString UFlib_DllHelper::GetMacFromLib () { char mac[200 ]; GetMac (mac); FString out = FString (mac); return out; }
运行测试
运行正常,打包以后也正常
动态方法 动态获取DLL
, 我们可以直接在函数库中使用
1 2 UFUNCTION (BlueprintCallable, BlueprintPure, Category = "Flib|DllHelper" , meta = (DisplayName = "GetMacDLL" )) static FString GetMacFromDLL () ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 typedef int (*_getMac) (char * mac) ;_getMac funcGetMac; void *v_dllHandle; FString UFlib_DllHelper::GetMacFromDLL () { FString folder ="DllImporter//ThirdParty//DLL" ; FString file = "ThirdPartyDLL.dll" ; FString filePath = *FPaths::ProjectPluginsDir () + folder + "/" + file; if (FPaths::FileExists (filePath)) { v_dllHandle = FPlatformProcess::GetDllHandle (*filePath); if (v_dllHandle != nullptr ) { funcGetMac = nullptr ; FString procName = "GetMac" ; funcGetMac = (_getMac)FPlatformProcess::GetDllExport (v_dllHandle, *procName); if (funcGetMac != nullptr ) { int idx = 0 ; char mac[200 ]; idx = int (funcGetMac (mac)); return FString (mac); } } } return TEXT ("" ); }
但是如果只是这样的话, 编辑器模式下没有问题, 打包以后会找不到DLL文件
解决方法是在*.build.cs
内对动态库添加包含
1 2 PublicLibraryPaths.Add (Path.Combine (ThirdPartyPath, "DLL" )); RuntimeDependencies.Add (new RuntimeDependency (Path.Combine (ThirdPartyPath, "DLL" ,"ThirdPartyDLL.dll" )));
成功
另外还有一种情况, DLL导出库是Lib的链接, 在编辑器下没有问题, 但是打包以后会提示招不到DLL
但是DLL是在你所在模块插件的目录里, 你需要手动复制到项目Binaries里去,或者用如下的方式自动拷贝并添加动态依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 string BinariesDirectory = Path.Combine (ProjectDirectory, "Binaries" , PlatformString); string SourceFile = Path.Combine (ThirdPartyPath, "assimp/bin" , PlatformString, "assimp-vc140-mt.dll" ); string TargetFile = Path.Combine (BinariesDirectory, "assimp-vc140-mt.dll" ); if (!Directory.Exists (BinariesDirectory)) { Directory.CreateDirectory (BinariesDirectory); } if (File.Exists (SourceFile) && !File.Exists (TargetFile)) { File.Copy (SourceFile, TargetFile, false ); } RuntimeDependencies.Add (Path.Combine (BinariesDirectory, "assimp-vc140-mt.dll" ));
如上图打包以后就放到了正确的目录