For a Windows application I'm trying to get CreateWindow() and WndProc() (or my versions of them) to be part of a singleton class that is created at the beginning of _tWinMain() but since trying to shift the functions to GameHandler.h and GameHandler.cpp I keep getting "unresolved external symbol _WinMain#16". They were originally global functions in main.cpp and everything was compiling fine then I decided to move them to GameHandler and ever since all I get is the unresolved external, even if I try to move them back to main.cpp.
I'm doing this in VS2010, the project was created as a Windows Application and there's no specific entry point set in properties (I double checked as every solution I've found so far says that it's because it's a console app - this isn't).
The code I currently have is shown below. The actual project has a couple of thousand lines of other code that I've left out as I don't think it's relevant (but will happily proved wrong. While the actual window creation code is related, I don't think the code itself is the problem (apart from what I left in), it's the location of GameWindowProc() &/or CreateGameWindow() or how they're called. The actual window creation code is taken from NeHe's tutorial. Trying to compile the following code only gives the aforementioned unresolved external.
main.cpp:
#include <Windows.h>
#include "GameManager.h"
#ifndef USEGMGR
bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag);
LRESULT CALLBACK GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
LPTSTR lpCmdLine, int nCmdShow)
{
GameManager::Startup();
GameManager* GMgr = GameManager::GetInstance();
GMgr->SetProgramState(GAME_MODE);
while(GMgr->GetProgramState() != GAME_MODE) // Normally this would be if (State != GAME_QUIT)
{ /* do game related stuff */ }
GameManager::Shutdown();
return 0;
}
#ifndef USEGMGR
bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag)
{
// Fairly complex but flexible creation code, taken from NeHe's tutorials. Of relevant interest is:
WNDCLASS wc; // Windows Class Structure
wc.lpfnWndProc = (WNDPROC) GameWindowProc; // WndProc Handles Messages
if (!RegisterClass(&wc)) // Attempt To Register The Window Class
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
return true;
}
LRESULT CALLBACK GameWindowProc(HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
// various custom message handling, if not processed:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
#endif
in GameManager.h:
#ifndef GAMEMANAGER_H
#define GAMEMANAGER_H
#define USEGMGR // makes CreateGameWindow() and GameWindowProc() methods in GameManager instead of global
#include <Windows.h>
enum ProgramState
{
GAME_MODE,
GAME_QUIT,
};
class GameManager
{
public:
static void Startup();
static void Shutdown();
static GameManager* GetInstance();
void Update(); // code not shown, check quit key etc
#ifdef USEGMGR
const bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag);
static LRESULT CALLBACK GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
void KillGameWindow(void);
const int GetProgramState() const;
void SetProgramState(const int& newMode);
private:
GameManager();
~GameManager();
GameManager(const GameManager&);
GameManager& operator=(const GameManager&);
HINSTANCE m_hInstance;
HWND m_hWnd;
HDC m_hDC;
static GameManager* s_instance;
int m_programState; // uses ProgramState enum
};
#endif
in GameManager.cpp:
#include "GameManager.h"
#include <Windows.h>
#include <assert.h>
#ifndef USEGMGR
extern bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag);
#endif
GameManager* GameManager::s_instance = NULL;
GameManager::GameManager(){}
GameManager::~GameManager(){}
void GameManager::Startup()
{
assert(s_instance == NULL);
s_instance = new GameManager;
#ifdef USEGMGR
if (! (s_instance->CreateGameWindow("Game Window", 800, 600, 32, true )) )
#else
if (! (CreateGameWindow("Game Window", 800, 600, 32, true )) )
#endif
assert("CreateGameWindow failed! Need an error here"); // Quit If Window Was Not Created - clean this up later
}
void GameManager::Shutdown()
{
assert(s_instance != NULL);
delete s_instance;
s_instance = NULL;
}
GameManager* GameManager::GetInstance(){return s_instance;}
void GameManager::Update(){/* msg handling, watch for quit key, etc */}
const int GameManager::GetProgramState() const{return s_instance->m_programState;}
void GameManager::SetProgramState(const int& newState){s_instance->m_programState = newState;}
#ifdef USEGMGR
const bool GameManager::CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag)
{
// Fairly complex but flexible creation code, taken from NeHe's tutorials. Of relevant interest is:
WNDCLASS wc; // Windows Class Structure
wc.lpfnWndProc = (WNDPROC) GameManager::GameWindowProc; // WndProc Handles Messages
if (!RegisterClass(&wc)) // Attempt To Register The Window Class
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
return true;
}
LRESULT CALLBACK GameManager::GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// various custom message handling, if not processed:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
#endif
As you can see, I've set up some preprocessor conditionals to switch between the troublesome functions being in main.cpp or as part of GameManager. Comment out #define USEGMGR at the beginning of GameManager.h to have them as global funcs in main.cpp.
Can someone please tell me what I'm doing wrong?
Edit: removed comment about not being able to quit if you get it to run.
The WinMain function cannot be a member function of a class, even a "singleton" class.
Since it functions as the "entry point" for the program, essentially replacing the main function you'd find in a traditional C++ application, it needs to be a free global function.
The message Unresolved external _WinMain#16 is simply the compiler's cryptic way of telling you that it cannot locate the expected entry point, named WinMain (plus some name mangling).
Add
#include <tchar.h>
to the top of main.cpp so that the _tWinMain macro gets defined properly.
What happens if you don't have the macro definition is that you end up with a function named _tWinMain() (or some mangled version of the name like ?_tWinMain##YGHPAUHINSTANCE__##0PADH#Z()) in the object file, but the linker and runtime initialization code are looking for WinMain() or wWinMain(). They don't find it.
<tchar.h> defines a macro that transforms the name _tWinMain() into one of the two names everything else is looking for. You must have had something including that header before you started your refactoring (quite possibly indirectly), and lost it somehow.
Or you can dispense with the macro version and name the function WinMain or wWinMain (either one should work, regardless of whether you're building for UNICODE or not). If you do that, just remember to change the LPTSTR parameter declaration to match the one you choose.
Related
I've been racking my brain on this for days, and could use some help! I'm able to detect a CBT hook using SetWindowsHookEx when it is hooked to the thread ID of my WPF application, but I'm not able to get it to hook to the Thread ID of another process window when that window becomes the foreground app.
Image 1: Shows that I CAN get the CBT hook for detecting window maximize on the main app's Thread ID
Image 2: Shows that I CANNOT get the CBT hook when listening to another app's Thread ID, and it will crash the app!
I want to avoid sending ThreadId=0 and making it a complete global hook, because I know that I only want to listen to the foreground app, not all apps on the desktop. I want to be able to listen to a few window events before they happen (WH_CBT does this from what I understand) for any window that currently has the foreground focus.
Again, the following code works when the current WPF app becomes the foreground app, but it fails when another app's window becomes the foreground (e.g. Notepad, Internet Explorer, File Explorer, Chrome, etc.).
Full Code: (link to github zip file)
Here are some snippets of the code to show what I did:
DLL that defines the callback (inject.dll):
inject.h: Snippet
typedef void(__stdcall* MYFUNCPTR)(int code, WPARAM wparam, LPARAM lparam);
extern "C" __declspec(dllexport) void Init(MYFUNCPTR funcPtr);
extern "C" __declspec(dllexport) LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam);
WPARAM wparam, LPARAM lparam);
MYFUNCPTR _handler = 0;
inject.cpp: Snippet
void Init(MYFUNCPTR funcPtr)
{
_handler = funcPtr;
}
LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code >= 0)
{
// Only send the code if you are about to MAXIMIZE
if (code == HCBT_MINMAX)
{
if (lparam == SW_MAXIMIZE)
{
_handler(0, wparam, lparam);
}
}
}
return CallNextHookEx(NULL, code, wparam, lparam);
}
DLL that sets the CBT hook (dllwrapper.dll):
dllwrapper.cpp: Snippet
// Load library in which we'll be hooking our functions.
HMODULE dll = LoadLibrary(L"inject.dll");
if (dll == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-LoadLibrary failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("LoadLibrary passed!");
// Get the address of the function inside the DLL.
MYPROC iaddr = (MYPROC)GetProcAddress(dll, "Init");
if (iaddr == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for Init failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for Init passed!");
iaddr(OnInjectionCallback);
// Get the address of the function inside the DLL.
HOOKPROC cbtProcAddress = (HOOKPROC)GetProcAddress(dll, "CbtProcCallback");
if (cbtProcAddress == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for CbtProcCallback failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for CbtProcCallback passed!");
// Hook the function
cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProcAddress, dll, _threadId);
if (cbtProcHook == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-SetWindowsHookEx cbtProcAddress failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("SetWindowsHookEx for cbtProcAddress passed!");
Snippet exporting to C#
typedef void(__stdcall* CodeCallback)(int code, WPARAM wparam, LPARAM lparam);
typedef void(__stdcall* MessageCallback)(const char* message);
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
__declspec(dllexport) bool StartHooks(unsigned int threadId, MessageCallback messageCallback, CodeCallback codeCallback);
__declspec(dllexport) void StopHooks();
#ifdef __cplusplus
}
#endif
NativeMethods.cs: Snippet of C# dll imports to the WPF app
public delegate void MessageCallback(string message);
public delegate void CodeCallback(int code, IntPtr wParam, IntPtr lParam);
[DllImport("dllwrapper.dll")]
public extern static bool StartHooks(uint threadId, MessageCallback messageHandler, CodeCallback codeHandler);
[DllImport("dllwrapper.dll")]
public extern static void StopHooks();
I can see from the messages in the WPF app window that the hook is passing and not returning any Win32 errors, but it's just not executing the callback when another window has focus (even when using the debugger).
Any help would be greatly appreciated!
Development Environment:
Windows 10 1909
VS2019 16.7.4
C# .NET Framework 4.7.2, C++
When the main app calls Init(), it is calling into its own instance of the DLL, and so is setting its own copy of _handler.
When your hook DLL is injected into another process, that process will get its own copy of the DLL, and thus its own copy of _handler. But Init() is never called on that DLL instance, so its copy of _handler is still 0 when your hook function is invoked inside that process. That is why the process crashes, since the hook is not checking for that condition.
Your DLL in another process can't call a function in your main app across process boundaries. You are going to have to change your hook function to instead use an IPC mechanism of your choosing to communicate with the main app process when _handler is 0. Window messages, pipes, mailslots, sockets, etc can be used for that communication.
In my .h file function mouseProc is declared as static(it has to be)
.h file
static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam);
initially i thought i would add &ui as a parameter to this function, but i am not able to do so. it gives me error "incompatible parameter type with HOOKPROC"
so, now i am not able to access the textboxes and labels in my UI by using
ui->textbox->apped(); how to solve this ?
---UPDATE as per suggestion of making ui static--------------
mainwindow.h
#pragma once
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "windows.h"
#include "windowsx.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT //Used to handle events
Q_DISABLE_COPY(MainWindow) //added
public:
MainWindow(QWidget* parent = 0);
~MainWindow(); //Destructor used to free resources
// Static method that will act as a callback-function
static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam);
// BOOL InitializeUIAutomation(IUIAutomation** automation);
static Ui::MainWindow* ui; // declared static,pointing to UI class
private:
// hook handler
HHOOK mouseHook;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <Windows.h>
#include <UIAutomation.h>
using namespace std;
Ui::MainWindow* MainWindow::ui = 0;
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
//, ui(new Ui::MainWindow)
{
ui = new Ui::MainWindow();
ui->setupUi(this);
HINSTANCE hInstance = GetModuleHandle(NULL);
// Set hook
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, &mouseProc, hInstance, 0);
// Check hook is correctly
if (mouseHook == NULL)
{
qWarning() << "Mouse Hook failed";
}
}
BOOL InitializeUIAutomation(IUIAutomation** automation)
{
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
(void**)automation);
return (SUCCEEDED(hr));
}
MainWindow::~MainWindow()
{
delete ui;
}
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
ui->textbox->append(string);
}
You can't add extra parameters to mouseProc. The compiler won't accept it, it needs to match the signature that SetWindowsHookEx() is expecting. If you resort to using a type-cast to force the compiler to accept it, the OS still won't know how to populate the new parameters with values at runtime when the hook is called, and you will just end up corrupting the call stack, and/or crashing your code.
To do what you want, you will simply have to store your ui pointer in global memory, or even make it be static as well. Somewhere that mouseProc can reach it.
As for the compiler error, what it says is correct - the MainWindow class you have shown does not have a member named textbox, which is why accessing ui->textbox (regardless of where ui will come from) fails to compile. So, you need to figure out where the textbox is really being stored, and then access it from THERE instead of from the MainWindow.
Sheesh. I've run into the infamous LNK2005 error when defining my class and I can't seem to place the issue.
(I'm tearing apart an equally infamous singleton of mine to reflect well, organization.) The initial said singleton was coded... ...in such a divergent, brilliant way... as to avoid all of the C++ OPP principles and concepts I was ignorant to at the time, but it worked! ....Somehow. Though some fluke of the simplest C++ concepts it did. Now I need organization, compilation speed, and advanced structuring techniques to make it work fast, and- you get it.
A-Anyway. After splitting it up, and having to rewrite some, I've noticed a necessity. I must declare multiple .cpp files simply because the compiler is irked massively by double declarations, and the usual header class definitions.
Additionally I've used preprocessor directives accordingly as applicable. But something still remains wrong.
Note(Edit): I've rewritten the question to provide error given.
Consider:
D3D.h
#include "Infinity.h"
class Direct3D :
public Infinity
{
public:
Direct3D();
~Direct3D();
IDXGISwapChain *Swapchain; //Display modes.
static ID3D11Device *Device;
static ID3D11DeviceContext *DeviceContext;
static ID3D11RenderTargetView *RenderTargetView;
void D3D_Start(float width, float height);
void D3D_Render();
void D3D_Terminate();
void ViewPort(float Height, float Width, float MaxDepth, float MinDepth, float TopLeftX, float TopLeftY);
}Direct3D;
...and Windows.h
#include "Infinity.h"
class Windows :
public Infinity
{
public:
Windows();
~Windows();
bool DisplayWindow(int width, int height, HINSTANCE hInstance);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
}Windows;
Finally, Infinity.h
#pragma once
class Infinity{
public:
Infinity();
~Infinity();
static HWND hWnd;
};
Whereas all implementations are in their respective .cpp files. Besides #pragma, I've used #ifndef ... #endif. I suspect that I may be inadvertently calling a kind of implementation by auto-initializing the classes in their header files. But it looks insanely kosher, and allows me to declare function members as:
Direct3D.D3D_Start() without stating a static member, Direct3D::D3D_Start().
Should my headers all be static?
Edit: Below, the .cpp file:
#include "stdafx.h"
#include "Infinity.h"
#include "Windows.h"
#include "Direct3D.h"
MSG msg;
float width = 1024;
float height = 768;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
windows.DisplayWindow(1280, 900, hInstance);
direct3D.D3D_Start(width, height);
direct3D.ViewPort(height, width, 1.0f, 0.0f, 0, 0);
while (WM_QUIT != msg.message){
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else{
direct3D.D3D_Render();
}
}
direct3D.D3D_Terminate();
return msg.wParam;
}
*Update the .cpp has been changed to show Niall's solution.
Edit:
Question:
Am I getting the LNK2005 issue because I auto-initialized my classes in their header files, considering the solution at Stack Overflow question:
VS 2010 C++ LNK2005 errors while using #pragma once and #ifndef
Which doesn't seem to work based my understanding of the solution.
Compiler
VS2013 returns:
Error 1 error LNK2005: "class Direct3D Direct3D" (?Direct3D##3V0#A) already defined in Direct3D.obj C:\Users\InfinityMachine\documents\visual studio 2013\Projects\Win32Project3\Win32Project3\Win32Project3.obj Win32Project3
Error 2 error LNK2005: "class Windows Windows" (?Windows##3V0#A) already defined in Win32Project3.obj C:\Users\InfinityMachine\documents\visual studio 2013\Projects\Win32Project3\Win32Project3\Windows.obj Win32Project3
Error 3 error LNK1169: one or more multiply defined symbols found C:\Users\InfinityMachine\documents\visual studio 2013\Projects\Win32Project3\Debug\Win32Project3.exe 1 1 Win32Project3
You declare class Direct3D... } Direct3D; and variable of the same name immediately. This would be the cause of such an error.
A variable of type Direct3D, named Direct3D (or otherwise) will be in each translation unit that includes that header, the same applies for Windows.
One possible resolution is to remove the variable declaration, another would be to move it and make it static, or in an anonymous namespace. Alternates include extern or implementing a singleton; which may be closer to the original intent.
Based on further discussions, an appropriate solution here is;
class Direct3D {};
extern Direct3D direct3D;
Then in the one of the implementation files
Direct3D direct3D;
This then declares the object as extern and provides a single instance of it.
I have this code:
void CALLBACK CTestTimeUpDlg::MyTimerProc(
HWND hWnd, // handle of CWnd that called SetTimer
UINT nMsg, // WM_TIMER
UINT_PTR nIDEvent, // timer identification
DWORD dwTime // system time
)
{
const int m_TimerValue=0;
double timeValueSec=m_TimerValue/1000.0;
CString valueString;
valueString.Format(L"%3.3f",timeValueSec);
m_TimerDisplayValue.SetWindowTextW(valueString);
}
void CTestTimeUpDlg::OnBnClickedButtonStart()
{
m_TimerValue=0;
m_Timer = SetTimer(1, 1, &CTestTimeUpDlg::MyTimerProc);
}
but when I compiled it, I am getting this error:
'CWnd::SetTimer' : cannot convert parameter 3 from 'void (__stdcall CTestTimeUpDlg::* )(HWND,UINT,UINT_PTR,DWORD)' to 'void (__stdcall *)(HWND,UINT,UINT_PTR,DWORD)'
the code is similar to the code from Microsoft documentation:
http://msdn.microsoft.com/en-us/library/49313fdf.aspx
You should make CTestTimeUpDlg::MyTimerProc static. However, by doing this, you can't access instance members such as m_TimerDisplayValue.
You shouldn't use callback in this case. Set lpfnTimer NULL, as the first timer in the sample of the link. That way, the timer posts the message WM_TIMER, and you can handle it by your non-static member function.
ADD:
Seems the document (plus my words above) is lacking in explanation.
Do as followings to implement a handler of WM_TIMER.
Declare handler in your class declaration:
afx_msg void OnTimer(UINT_PTR nIDEvent);
In your cpp file, add message mapping:
BEGIN_MESSAGE_MAP(CTestTimeUpDlg, ...)
ON_WM_TIMER()
END_MESSAGE_MAP()
and implementation:
void CTestTimeUpDlg::OnTimer(UINT_PTR nIDEvent)
{
// your code here...
}
I began C++ quite recently and I obviously have the famous LNK2019 issue. I roamed a few hours on google but nothing solved my problem.
My project is half way coded, since I separate the view and the model.
I work with Visual Studio 2010.
Here is the class whose function is not retrieved:
Display.h:
#ifndef DEF_DISPLAY
#define DEF_DISPLAY
#include <Windows.h>
#include <exception>
class Display{
public:
HWND mainWindow, gameWindow;
WNDCLASS mainClass, gameClass;
public:
Display();
static LRESULT CALLBACK mainWindowProc(HWND mainWin, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK gameWindowProc(HWND gameWin, UINT message, WPARAM wParam, LPARAM lParam);
**int run();** // This function is not retrieved by the linker.
};
#endif
And here is the Display.cpp:
#include "Display.h"
HINSTANCE instanceMain = 0, instanceGame = 0;
Display::Display(){...}
LRESULT CALLBACK Display::mainWindowProc(HWND mainWin, UINT message, WPARAM wParam, LPARAM lParam){...}
LRESULT CALLBACK Display::gameWindowProc(HWND gameWin, UINT message, WPARAM wParam, LPARAM lParam){...}
int run(){
MSG message;
while(GetMessage(&message, 0, 0, 0)){
TranslateMessage(&message);
DispatchMessage(&message);
}
return message.wParam;
}
And finally here is my main.cpp:
#include "Display.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow){
Display game;
return game.run();
}
I did not finished to code my project because I found out that issue when building it:
1> All outputs are up-to-date.
1>main.obj : error LNK2019: unresolved external symbol "public: int __thiscall Display::run(void)" (?run#Display##QAEHXZ) referenced in function _WinMain#16
1>C:\Users\glembalis\Documents\Visual Studio 2010\Projects\pendu\Debug\pendu.exe : fatal error LNK1120: 1 unresolved externals
1>
1>Build FAILED.
I don't know where the error can occur.
Display.h and Display.cpp are included in the project
The option in Project > Properties > Linker > System > SubSystem is "Windows"
I do not use external libraries (only Windows.h and exception)
The compiler seems to work well. I don't really care if the program works properly, I would correct it later. For now, this linker issue is my major concern! I guess it is just a tiny little stupid mistake, but I cannot find it out!
Thanks to everyone for your time and attention, looking forward to have your answers! Last, I apologise but english is not my native language and I may have written some mistakes.
Have a nice day!
NoobFeeder
Your definition (implementation) has the wrong signature.
It should look like this:
int Display::run(){
This tells the compiler that your run is the one that's a member of your Display class.
Currently you have implemented a free function called run.