error LNK2001: unresolved external symbol Unreal Engine 4 Using Plugins (UE4) - c++

I am trying to import a third party library for UE4 and use it in an actor. The UE4 documentation recommends creating a plugin to accomplish this and provides an auto generated template which i am trying to test currently.
I have created a blank C++ UE4 Project with a new third party custom plugin and an actor class in which to use the plugin/library.
This is my build.cs file for the main project:
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class TestGame : ModuleRules
{
public TestGame(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "CustomTestPlugin" });
PrivateDependencyModuleNames.AddRange(new string[] { "CustomTestPlugin" });
PublicIncludePaths.AddRange(new string[] { "../Plugins/CustomTestPlugin/Source/CustomTestPlugin/Public" });
// 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
}
}
and have included the plugin in the actor cpp file using
#include "CustomTestPlugin.h"
as well as instantiating it in the same file:
FCustomTestPluginModule pluggin = FCustomTestPluginModule::FCustomTestPluginModule();
when I compile without the above it builds fine but when i declare the pluggin variable it gives the following error:
TestActor.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl FCustomTestPluginModule::StartupModule(void)" (?StartupModule#FCustomTestPluginModule##UEAAXXZ)
CustomTestPlugin.h is as follows:
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Modules/ModuleManager.h"
class FCustomTestPluginModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
//FCustomTestPluginModule();
virtual void StartupModule() override;
virtual void ShutdownModule() override;
private:
/** Handle to the test dll we will load */
void* ExampleLibraryHandle;
};
and the cpp file:
// Copyright Epic Games, Inc. All Rights Reserved.
#include "CustomTestPlugin.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#include "CustomTestPluginLibrary/ExampleLibrary.h"
#define LOCTEXT_NAMESPACE "FCustomTestPluginModule"
//FCustomTestPluginModule::FCustomTestPluginModule() {
// UE_LOG(LogTemp, Warning, TEXT("CustomPluConstructed"));
//}
void FCustomTestPluginModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// Get the base directory of this plugin
FString BaseDir = IPluginManager::Get().FindPlugin("CustomTestPlugin")->GetBaseDir();
// Add on the relative location of the third party dll and load it
FString LibraryPath;
#if PLATFORM_WINDOWS
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/CustomTestPluginLibrary/Win64/ExampleLibrary.dll"));
#elif PLATFORM_MAC
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/CustomTestPluginLibrary/Mac/Release/libExampleLibrary.dylib"));
#elif PLATFORM_LINUX
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/CustomTestPluginLibrary/Linux/x86_64-unknown-linux-gnu/libExampleLibrary.so"));
#endif // PLATFORM_WINDOWS
ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;
if (ExampleLibraryHandle)
{
// Call the test function in the third party library that opens a message box
ExampleLibraryFunction();
}
else
{
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));
}
}
void FCustomTestPluginModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
// Free the dll handle
FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);
ExampleLibraryHandle = nullptr;
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FCustomTestPluginModule, CustomTestPlugin)
any help in resolving this would be greatly appreciated thanks!

You should not need to instantiate your module manually. The module is loaded and instantiated by the engine at startup if it is referenced in your project.
If for some reason you need to get a reference to your module's singleton, you can use
FModuleManager::LoadModuleChecked<FYourModuleType>("YourModule");

Related

How to export a function of a regular MFC DLL that is statically linked to MFC to use with a non MFC Win32 Console App in C++

I am very new in C++ world and this kind of task.
I am having a hard time to resolve this issue.
Any help is kindly appreciated!
I have created a regular MFC DLL that is statically linked to MFC. (This is the first time i ever created a MFC project)
MFC DLL Header File Content
// Serial.h
#pragma once
#ifndef __AFXWIN_H__
#error "include 'pch.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
class SerialApp : public CWinApp
{
public:
SerialApp();
__declspec(dllexport) void __cdecl SerialApp::Init();
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
MFC DLL Definition File Content
// Serial.cpp
#pragma once
#include "pch.h"
#include "framework.h"
#include "Serial.h"
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
BEGIN_MESSAGE_MAP(SerialApp, CWinApp)
END_MESSAGE_MAP()
SerialApp::SerialApp()
{
}
SerialApp theApp;
BOOL SerialApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
extern "C"
{
__declspec(dllexport) void __cdecl SerialApp::Init()
{
AfxDebugBreak();
std::cout << "Succeded";
}
}
Win32 Console Application Content
#include <iostream>
#include <Windows.h>
int main()
{
//Load the DLL
HMODULE lib = LoadLibrary(L"D:\\C++ PROJECTS\\serial\\Debug\\Serial.dll");
//Create the function
typedef void(*Init_t)(void);
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
std::cout << GetLastError(); // This output's 127
if (!Serial) {
//ERROR. Handle it.
}
__declspec(dllimport) void __cdecl Init(void);
//Init(); //LNK2019 unresolved external symbol "__declspec(dllimport) void __cdecl Init(void)"
std::getchar();
}
When i use this approach:
__declspec(dllimport) void __cdecl Init(void);
Init();
//I am getting the linker error LNK2019 unresolved external symbol "__declspec(dllimport) void __cdecl Init(void)"
When i use this approach:
typedef void(*Init_t)(void);
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
std::cout << GetLastError();
//I am getting error code 127 from the GetLastError() function. (The specified procedure could not be found)
When i use this approach:
#include "Serial.h"
int main()
{
SerialApp pSerial;
pSerial.Init();
std::getchar();
}
//Serial.h forces me to include 'pch.h' before itself. if i include 'pch.h' into Win32 Console App before Serial.h It end's up with about 1000's of errors.
For Win32 Console Application Project:
1. C/C++ -> General -> Additional Include Directories is set to: D:\C++ PROJECTS\serial\Serial
2. Linker -> Input -> Additional Dependencies is set to : Serial.lib
3. Both Serial.lib and Serial.dll are included in the project and in the Debug folder.
4. Both MFC Dll Project and Win32 Console Projects are compiled in Debug x86 mode.
Questions
What i am doing wrong?
Is this even possible?
Thank you!
The question is resolved by #dxiv's comment:
You cannot import a member function like SerialApp::Init to a non-MFC app,
because that app does not know about the SerialApp class, and cannot
know about it since SerialApp is derived from CWinApp which is an MFC
class, while your app is non-MFC. If you want to export a free
function from the DLL, then make it __declspec(dllexport) void __cdecl Init(void); outside the SerialApp class, or any class for that matter.
1. I removed the declaration __declspec(dllexport) void __cdecl SerialApp::Init(); from the header file.
2. Rewrite the definition of Init() in the Serial.cpp file as:
extern "C"
{
__declspec(dllexport) void __cdecl Init()
{
std::cout << "Succeded";
}
}
3. I call the function in Win32 Console App as:
int main()
{
//Load the DLL
HMODULE lib = LoadLibrary(L"D:\\C++ PROJECTS\\serial\\Debug\\Serial.dll");
//Create the function
typedef void(*Init_t)(void); // <- You can name Init_t whatever you want.
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
if (!Serial) {
std::cout << GetLastError();
return 1;
}
Serial(); //<- Init() Function Call from Serial.dll
std::getchar();
return 0;
}
And all worked great!
Thank you everyone, who make time to read and answer my Question!

UWP C# app calling Windows Runtime Component written in C++

I am trying to create a Windows Runtime(WinRT) Component written in C++(c++-cx) which can be called from my UWP C# app. I followed this MSDN Tutorial
It all went fine. I am able to build & run the code/sample specified in the above link on both Windows-10 Desktop & Mobile
I then tried to create a even simpler WinRT Component. I followed the same steps as above tutorial. Created a Windows Runtime Component project (File->New->Project->Visual C++ ->Windows->Universal->Windows Runtime Component(Universal Windows))
Now my class has only one function, getNum which basically returns a uint16
This is my Class header file
#pragma once
#include <collection.h>
namespace WRT_sample
{
public ref class Class1 sealed
{
public:
Class1();
uint16 getNum();
};
}
This is the corresponding cpp file:
#include "Class1.h"
using namespace WRT_sample;
using namespace Platform;
Class1::Class1()
{
}
uint16 Class1::getNum()
{
return 100;
}
I am using the same class names(Class1.h & Class1.cpp) which VS-2015 provides when I create a new WinRT project.
This is how I make a call to WinRT class from my C# code:
namespace CS_WRT_sample
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
initWRT();
}
void initWRT()
{
try
{
var nativeObj = new Class1();
var num = nativeObj.getNum();
this.Result2.Text = "Num from Cpp: " + num.ToString();
Debug.WriteLine("Num from Cpp: " + num);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
this.Result3.Text = ex.Message;
}
}
}
}
I am able to build & run my code on Desktop(x86/x64 Local Machine), but when I try to run on Mobile(x86 Emulator or ARM device), it fails with the following error:
Exception thrown: 'System.IO.FileNotFoundException' in CS_WRT_sample.exe
The specified module could not be found. (Exception from HRESULT: 0x8007007E)**
This is the stack trace which I see:
System.StubHelpers.StubHelpers.GetWinRTFactoryObject(IntPtr pCPCMD)
at WRT_sample.Class1..ctor()
at CS_WRT_sample.MainPage.initWRT()
My VS-2015 details:
MS Visual Studio Professional 2015
Version 14.0.25123.00 Update 2
MS .NET Framework
Version 4.6.01038
I am not sure, why I am hitting the issue, as I followed the same steps mentioned in the MSDN tutorial.
Any help will be highly appreciated.
You will run into this if you use a direct reference to a C++ winmd, instead of a P2P reference. This is easy to check in your .csproj:
For example, your .csproj should not have this line:
..\Debug\Abc_def\Abc_Def.winmd
Instead, consider using something like:
{1ee77824-eaa8-40f1-9b56-6f8ffa44e727}
Abc_Def

Unit testing Inconsistent dll linkage leads to compilation error

New to c++ and trying to test a dll but keep getting
warning C4273: 'CRootFinder::SquareRoot' : inconsistent dll linkage
RootFinder.h
#ifdef MY_EXPORTS
#define API _declspec(dllexport)
#else
#define API _declspec(dllimport)
#endif
class API CRootFinder {
public:
CRootFinder(void);
double SquareRoot(double v);
};
RootFinder.cpp
#include "stdafx.h"
#include "RootFinder.h"
double CRootFinder::SquareRoot(double v)
{
return 0.0;
}
Builds but gets warning above.
Added reference to dll to unit test project
unittest1.cpp
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../c source/RootFinder.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Tests
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
CRootFinder rooter;
Assert::AreEqual(
// Expected value:
0.0,
// Actual value:
rooter.SquareRoot(0.0),
// Tolerance:
0.01,
// Message:
L"Basic test failed",
// Line number - used if there is no PDB file:
LINE_INFO());
}
};
}
Won't build
Error 2 error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall
CRootFinder::CRootFinder(void)" (__imp_??0CRootFinder##QAE#XZ)
referenced in function "public: void __thiscall
Tests::UnitTest1::TestMethod1(void)"
(?TestMethod1#UnitTest1#Tests##QAEXXZ)
Compile dll with MY_EXPORTS preprocessor marco. Add use it in test without MY_EXPORTS definition macro.
In Visual Studio you can do that: Project right click->Propertis->C/C++->Preprocessor->Preprocessor Definitions, just add MY_EXPORTS to the list for dll project, and leave that list without MY_EXPORTS for test project.
And you need define constructor CRootFinder() in RootFinder.cpp.

Use C++/CLI Library in C++ native code and how to link

I want to use some code that executes a http-post, and because I'm not too familiar with c++ and what libraries you can use, and I am probably too dumb to get libcurl and curlpp to work, I found a link explaining how to use the .net version.
Alright so I created a class. Header File:
public ref class Element
{
public:
Element();
virtual ~Element();
void ExecuteCommand();
};
Class file:
#include "Element.h"
Element::Element()
{
}
Element::~Element()
{
Console::WriteLine("deletion");
}
void Element::ExecuteCommand(){
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create("http://www.google.com"));
request->MaximumAutomaticRedirections = 4;
request->MaximumResponseHeadersLength = 4;
request->Credentials = gcnew NetworkCredential("username", "password", "domain");
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
Console::WriteLine("Content length is {0}", response->ContentLength);
Console::WriteLine("Content type is {0}", response->ContentType);
// Get the stream associated with the response.
Stream^ receiveStream = response->GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader^ readStream = gcnew StreamReader(receiveStream, Encoding::UTF8);
Console::WriteLine("Response stream received.");
Console::WriteLine(readStream->ReadToEnd());
response->Close();
readStream->Close();
}
If I set the configuration type of this project to Application (exe), and create a new .cpp file where I create an Instance of this Element it works fine.
But my question is: Is it possible to create a .dll/.lib Library from this project and use it in a C++ project without CLI? (I don't want to use ^ for pointers :( )
Even if it's not possible, I have another problem.
When I link the library in a C++/CLI project. I get
unresolved token (06000001) Element::.ctor
unresolved token (06000002) Element::~Element
unresolved token (06000003) Element::ExecuteCommand
3 unresolved externals
the code for main.cpp in the second project is just the following:
#include <Element.h>
int main(){
return 0;
}
Thank you
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries.
If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side:
I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.

managed c to call an unmanaged c dll , unresolved token

I have 1 native c++ dll, CppApp, another project is managed c++, GatWayLibrary, with /clr
In GatewayLibrary, I called functions from native CppApp dll.
but I got unresolve token errors.
Here are my code snips:
CppApp.h
=========
#ifdef CPPAPP_EXPORTS
#define CPPAPP_API __declspec(dllexport)
#else
#define CPPAPP_API __declspec(dllimport)
#endif
class CPPAPP_API CppApp
{
public:
CppApp();
~CppApp();
ContextManager & contextMgr() { return m_rplContextMng; }
INativeListener* m_listener;
void registerListener(INativeListener* listener)
{
m_listener = listener;
}
...........
}
In separate project, GateWaylibrary, wrap the native dll as
#include "../CppApp/CppApp.h"
#include <vcclr.h>
using namespace System;
using namespace System::Runtime::InteropServices;
#pragma comment(lib, "CppApp.lib")
namespace GatewayLibrary{
//.net equvelant of the argument class
public ref class DotNetEventArg{
internal:
//contructor takes native version of argument to transform
DotNetEventArg(const NativeCPPArgs& args) {
....
...
}
the managed c++ has the linking errors as unresolved tokens for all the function calls from the native c++.
I did include the CppApp.lib as Additional Dependencies
and the directory.
Can anyone please help? many thanks ahead.
Edit:
here is of the place I called the native c++
`GatewayLibrary::EventGateway::EventGateway()
{
nativeCode_ = new CppApp();
//note; using 'this' in ctor is not a good practice
nativeListener_ = new NativeListenerImp(this);
//register native listener
nativeCode_->registerListener(nativeListener_);
}`