winrt::hresult_class_not_registered using Unreal Engine 4
Zaratusa
1
Reputation point
Hi,
I've followed the WinRT in Unreal tutorial to integrate the Vungle SDK for Windows to build a Win64 game with in-game ads in Unreal Engine 4.27.
Compiling and using WinRT functions, as well as loading the VungleSDK.winmd works fine, but calling a Vungle function causes a "class not registered" error.
Is there an extra step involved, when using the WinRT in Unreal tutorial for Win64 instead of HoloLens games?
packages.config file:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.6" targetFramework="native" />
<package id="VungleSDK" version="6.11.0" targetFramework="native" />
</packages>
.Build.cs file:
// these parameters mandatory for winrt support
bEnableExceptions = true;
bUseUnity = false;
CppStandard = CppStandardVersion.Cpp17;
PublicSystemLibraries.AddRange(new string[] { "shlwapi.lib", "runtimeobject.lib" });
// prepare everything for nuget
string NugetFolder = Path.Combine(PluginDirectory, "Intermediate", "Nuget");
Directory.CreateDirectory(NugetFolder);
string BinariesSubFolder = Path.Combine("Binaries", "ThirdParty", Target.Type.ToString(), Target.Platform.ToString(), Target.Architecture);
PrivateDefinitions.Add(string.Format("THIRDPARTY_BINARY_SUBFOLDER=\"{0}\"", BinariesSubFolder.Replace(@"\", @"\\")));
string BinariesFolder = Path.Combine(PluginDirectory, BinariesSubFolder);
Directory.CreateDirectory(BinariesFolder);
ExternalDependencies.Add("packages.config");
// download nuget
string NugetExe = Path.Combine(NugetFolder, "nuget.exe");
if (!File.Exists(NugetExe))
{
using (System.Net.WebClient myWebClient = new System.Net.WebClient())
{
// we aren't focusing on a specific nuget version, we can use any of them but the latest one is preferable
myWebClient.DownloadFile(@"https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", NugetExe);
}
}
// run nuget to update the packages
{
var StartInfo = new System.Diagnostics.ProcessStartInfo(NugetExe, string.Format("install \"{0}\" -OutputDirectory \"{1}\"", Path.Combine(ModuleDirectory, "packages.config"), NugetFolder));
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
var ExitCode = Utils.RunLocalProcessAndPrintfOutput(StartInfo);
if (ExitCode < 0)
{
throw new BuildException("Failed to get nuget packages. See log for details.");
}
}
// get list of the installed packages, that's needed because the code should get particular versions of the installed packages
string[] InstalledPackages = Utils.RunLocalProcessAndReturnStdOut(NugetExe, string.Format("list -Source \"{0}\"", NugetFolder)).Split(new char[] { '\r', '\n' });
// winmd files of the packages
List<string> WinMDFiles = new List<string>();
// WinRT lib for some job
string VunglePackage = InstalledPackages.FirstOrDefault(x => x.StartsWith("VungleSDK"));
if (!string.IsNullOrEmpty(VunglePackage))
{
string QRFolderName = VunglePackage.Replace(" ", ".");
// copying dll and winmd binaries to our local binaries folder
// !!!!! please make sure that you use the path of file! Unreal can't do it for you !!!!!
string WinMDFile = Path.Combine(NugetFolder, QRFolderName, @"lib\uap10.0\VungleSDK.winmd");
File.Copy(WinMDFile, Path.Combine(BinariesFolder, "VungleSDK.winmd"), true);
// also both both binaries must be in RuntimeDependencies
RuntimeDependencies.Add(Path.Combine(BinariesFolder, "VungleSDK.winmd"));
//add winmd file to the list for further processing using cppwinrt.exe
WinMDFiles.Add(WinMDFile);
}
if (Target.Platform == UnrealTargetPlatform.Win64)
{
// Microsoft.VCRTForwarders.140 is needed to run WinRT dlls in Win64 platforms
string VCRTForwardersPackage = InstalledPackages.FirstOrDefault(x => x.StartsWith("Microsoft.VCRTForwarders.140"));
if (!string.IsNullOrEmpty(VCRTForwardersPackage))
{
string VCRTForwardersName = VCRTForwardersPackage.Replace(" ", ".");
foreach (var Dll in Directory.EnumerateFiles(Path.Combine(NugetFolder, VCRTForwardersName, "runtimes/win10-x64/native/release"), "*_app.dll"))
{
string newDll = Path.Combine(BinariesFolder, Path.GetFileName(Dll));
File.Copy(Dll, newDll, true);
RuntimeDependencies.Add(newDll);
}
}
}
// get WinRT package
string CppWinRTPackage = InstalledPackages.FirstOrDefault(x => x.StartsWith("Microsoft.Windows.CppWinRT"));
if (!string.IsNullOrEmpty(CppWinRTPackage))
{
string CppWinRTName = CppWinRTPackage.Replace(" ", ".");
string CppWinRTExe = Path.Combine(NugetFolder, CppWinRTName, "bin", "cppwinrt.exe");
string CppWinRTFolder = Path.Combine(PluginDirectory, "Intermediate", CppWinRTName);
Directory.CreateDirectory(CppWinRTFolder);
// all downloaded winmd file with WinSDK to be processed by cppwinrt.exe
var WinMDFilesStringbuilder = new System.Text.StringBuilder();
foreach (var winmd in WinMDFiles)
{
WinMDFilesStringbuilder.Append(" -input \"");
WinMDFilesStringbuilder.Append(winmd);
WinMDFilesStringbuilder.Append("\"");
}
// generate winrt headers and add them into include paths
var StartInfo = new System.Diagnostics.ProcessStartInfo(CppWinRTExe, string.Format("{0} -optimize -input \"{1}\" -output \"{2}\"", WinMDFilesStringbuilder, Target.WindowsPlatform.WindowsSdkVersion, CppWinRTFolder));
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
var ExitCode = Utils.RunLocalProcessAndPrintfOutput(StartInfo);
if (ExitCode < 0)
{
throw new BuildException("Failed to get generate WinRT headers. See log for details.");
}
PrivateIncludePaths.Add(CppWinRTFolder);
}
else
{
// fall back to default WinSDK headers if no winrt package in our list
PrivateIncludePaths.Add(Path.Combine(Target.WindowsPlatform.WindowsSdkDir, "Include", Target.WindowsPlatform.WindowsSdkVersion, "cppwinrt"));
}
Module:
void StartupModule() override
{
const FString LibrariesDir = FPaths::ProjectPluginsDir() / "Vungle" / THIRDPARTY_BINARY_SUBFOLDER;
FPlatformProcess::PushDllDirectory(*LibrariesDir);
const FString DllName = "VungleSDK.winmd";
if (!FPlatformProcess::GetDllHandle(*DllName))
{
UE_LOG(LogVungle, Warning, TEXT("Dll \'%s\' can't be loaded from \'%s\'"), *DllName, *LibrariesDir);
}
FPlatformProcess::PopDllDirectory(*LibrariesDir);
init_apartment(apartment_type::single_threaded);
const FString InAppID = TEXT("Test");
std::string AppID = TCHAR_TO_UTF8(*InAppID);
auto instance = AdFactory::GetInstance(to_hstring(AppID));
}
Sign in to answer