提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
由于本人最近需要用C#给UE开发一个功能,所以想到了C++调用C#库函数的方法,查阅了CSDN和虚幻官方论坛等很多资料,遇到了很多坑,分享下经历同时作为笔记。
由于网上很多教程和资料都已经过时导致很多方式方法并不适合目前的虚幻4.26版本。
答案是:.Net Framework 4 【当然也许虚幻c++用的Api不一样需要的C#目标框架也不同,也许随着时间推移虚幻可以支持更高版本,C++代码会正在后面贴出】。
提示:本节以下踩坑记录
看到官方的一篇文绉绉 说对Net Core3.1长期支持 作为这篇文章开发C#服务器相关的目标框架。因此我尝试了
我在C++内调用时候遇到无法加载dll的提示。里面有句话就是说框架应该是.Net Framework 4
答案是:UnmanagedExport 功能是将托管函数导出让C++调用
如图所示来搜索安装。【下图其他版本试了几次,反而无法调用,也许是我没用对】
如果搜索没有本文件可以通过
https://www.nuget.org/packages/UnmanagedExports
下载
①它编译完后是类似于C++的结构需要2个方法代替1个方法,可能描述不太好,还是看图吧。
②需要1个 void 开头的空方法,后来这个是非必须我也没测试了。
https://forums.unrealengine.com/t/is-it-possible-to-call-a-managed-net-dll-from-ue4-c-project/281570/4
这是官方论坛上老外的提示,截图是网页自动翻译的。
③不建议使用[DllExport] 无参数的,虽然插件里提示可以使用,但是1个dll里面只能用11个否则就会出错,出现的错误好像和。
C++内调试到执行方法返回参数时候会报以下错误,好像和使用其他目标框架报的错误类似。
提示:本节以下踩坑记录
由于没明白他的机制,还以为是它编译错乱
奇葩图1:
奇葩图2:以为只写[DllExport] 就不会出现了
奇葩图3:调用结果【至少是能调用了这图算是我1天半的成果了】
以为使用了升级版本旧可以避免这个错误了
然而在使用本侧率升级框架到4.6.2 以及UnmanagedExport 升级到第三个版本发现到了C++还是无法调用,所报的错误和目标框架不符合相同的错误。
代码如下(示例):
namespace Frame4Ue4ForCq888
{
public class dlltest
{
//必须要有空方法
static public void AFunction()
{
CCC();
}
//[DllExport]默认无参数的1个dll只能由1个所以我这里全用的是带有方法名称标签的
[DllExport("GetStrb", CallingConvention = CallingConvention.Winapi)]
static public string GetStrb()
{
return GetStrbb();
}
//类似C++ .h 和.cpp文件的2个方法
[DllExport("GetStrb", CallingConvention = CallingConvention.Winapi)]
static public string GetStrbb()
{
string str = "bb";
return str;
}
[DllExport("GetInt", CallingConvention = CallingConvention.Winapi)]
static public int GetInt()
{
return GetInt5();
}
[DllExport("GetInt", CallingConvention = CallingConvention.Winapi)]
static public int GetInt5()
{
return 5555;
}
[DllExport("CC", CallingConvention = CallingConvention.Winapi)]
static public void CC()
{
CCC();
}
[DllExport("CC", CallingConvention = CallingConvention.Winapi)]
static public void CCC()
{
}
}
}
第二个类
namespace Frame4Ue4ForCq888
{
public class MyDllTest2
{
static public void AFunction()
{
}
[DllExport("GetStrC", CallingConvention = CallingConvention.Winapi)]
static public string GetStrC()
{
return GetStrcc();
}
[DllExport("GetStrC", CallingConvention = CallingConvention.Winapi)]
static public string GetStrcc()
{
string str = "cc";
return str;
}
static public void CC()
{
CCC();
}
static public void CCC()
{
}
}
}
如果遇到问题可以只测试1对
②MyBpPlugin.build.cs 内添加dll引用,否则也会报和目标框架不对的类似错误。【代码内注释 -----新增的 表示是自己添加上的 其他都是默认创建的】
// Some copyright should be here...
using UnrealBuildTool;
using System.IO;
public class MyBpPlugin : ModuleRules
{
//--------------------------------------新增的
private string ModulePath
{
get
{
return ModuleDirectory;
}
}
//--------------------------------------新增的
private string ThirdPartyPath
{
get
{
return Path.GetFullPath(Path.Combine(ModulePath, "../../MyDll/Win64/"));
}
}
//这些应该是跟打包有关//--------------------------------------新增的
public void LoadxxxLib()
{
//第一个 半成品的版本
PublicDelayLoadDLLs.Add("Frame4UE4forcq8.dll");
RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(ThirdPartyPath, "Frame4UE4forcq8.dll")));
//第二个 测试完全正确版本
PublicDelayLoadDLLs.Add("Frame4Ue4ForCq888.dll");//确实不需要写具体路径了!!
RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(ThirdPartyPath, "Frame4Ue4ForCq888.dll")));
return;
}
public MyBpPlugin(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 ...
}
);
LoadxxxLib();//----------------------新增的
}
}
①MyBpPluginBPLibrary.h
UCLASS()
class UMyBpPluginBPLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Execute Sample function", Keywords = "MyBpPlugin sample test testing"), Category = "MyBpPluginTesting")
static float MyBpPluginSampleFunction(float Param);
public:
// 蓝图调用Dll --------新增的
UFUNCTION(BlueprintCallable, Category = "My Dll")
static bool CallDLL(FString folder, FString name, FString funcNam);
};
②MyBpPluginBPLibrary.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "MyBpPluginBPLibrary.h"
#include "MyBpPlugin.h"
typedef int(*_MyIntType)(int lastInt);
typedef char* (*_MyCharType)(char* parameterText);
UMyBpPluginBPLibrary::UMyBpPluginBPLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
float UMyBpPluginBPLibrary::MyBpPluginSampleFunction(float Param)
{
return -1;
}
//-----------------新增的
bool UMyBpPluginBPLibrary::CallDLL(FString folder, FString name, FString funcName)
{
FString filePath = *FPaths::ProjectPluginsDir() + folder + "/" + name;
if (FPaths::FileExists(filePath))
{
void* DLLHandle;
DLLHandle = FPlatformProcess::GetDllHandle(*filePath); // Retrieve the DLL.
if (DLLHandle != NULL)
{
_MyCharType DLLFuncPtr = NULL;
FString procName = funcName;
DLLFuncPtr = (_MyCharType)FPlatformProcess::GetDllExport(DLLHandle, *procName);
if (DLLFuncPtr != NULL)
{
char* input = "hello, test info";
char* result = DLLFuncPtr(input);
//GEngine->AddOnScreenDebugMessage(-1, 20.0, FColor::Red, input);
GEngine->AddOnScreenDebugMessage(-1, 10.0, FColor::Red, result);
return true;
}
return false;
}
}
return false; // Return an error.
}
提示:本节以下踩坑记录
C++调用遇到的坑
①上面的是工程插件路径,下面的是虚幻官方的插件路径。请务我们自己创建的插件必使用上方的。
FString filePath = *FPaths::ProjectPluginsDir() + folder + "/" + name;
FString filePath = *FPaths::EnginePluginsDir() + folder + "/" + name;
②调试返回null一般都是路径错误了
if (FPaths::FileExists(filePath))
③GetDllHandle 获得null 可能就是前面说的C#dll里面没有 一个void的函数 必须要有一个。
DLLHandle = FPlatformProcess::GetDllHandle(*filePath);
④DLLFuncPtr 这里返回不为kull 而在返回的参数计算时候 出问题,可能就是目标框架不对,或者C#内 UnmanagedExport 使用版本不对前面有说过第三个版本配合4.6.2好像并不能被调用,还有就是[DllExport] 没有字符串标签数量可能超过1对了。
char* result = DLLFuncPtr(input);
总之最容易出问题并不是C++ ,而是C#没按照相关目标框架使用,或者DllExport写法上有问题。
C#编译完毕后勤使用反编译软件查看如果出现如图情况说明编译有问题。
可以通过下载Reflector.NET来查看编译好的DLL文件
https://blog.csdn.net/yycocl/article/details/83273858
https://blog.csdn.net/yycocl/article/details/83275969
https://blog.csdn.net/baidu_27276201/article/details/75675836?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165103612716782248585611%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165103612716782248585611&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-6-75675836.142v9pc_search_result_cache,157v4control&utm_term=UE+%E8%B0%83%E7%94%A8dll%E5%86%85%E7%9A%84%E6%96%B9%E6%B3%95
https://forums.unrealengine.com/t/communication-between-c-dllexport-function-and-ue4-strings-problem/31583/5
https://forums.unrealengine.com/t/is-it-possible-to-call-a-managed-net-dll-from-ue4-c-project/281570/4