Fixing Linker Errors In .NET CLI Application SCUMM VM

I am new to C++, although I am an experienced C# developer.

I am trying to challenge myself by writing a .NET CLI wrapper around Scumm VM.

I have created CLI project called CLRScrumm. It is currently full of empty methods.

My strategy is to copy sdl.h, sdl-events and sdl-graphics, rename them as clr-xxx and gut them. Note that the OSystem_CLR is based on sdl.h

My end goal is for the C# to pass in a callback function which can be called from clr-graphics.copyRectToScreen.

I managed to those class skeletons compile, but not link. I guess I must be missing some function implementations somewhere, but I can't for the life of me
see where. The errors from the linker are very cryptic.

I would appreciate if someone would:
1. Give me a general strategy for fixing these errors
2. Point me in the write direction for fixing them.

Note. I feel really guilty sticking in reams of code, like I have but I don't know of another way.

Here are a couple of the linker errors.
Error LNK2020 unresolved token (0A00010E) "public: __thiscall Common::String::String(class Common::String const &)" (??0String@Common@@$$FQAE@ABV01@@Z) CLRScumm D:\ScummVM\GIT\dists\CLRScumm\clr-graphics.obj 1
Error LNK2028 unresolved token (0A000112) "public: __thiscall Common::String::String(class Common::String const &)" (??0String@Common@@$$FQAE@ABV01@@Z) referenced in function "public: __thiscall Common::Event::Event(struct Common::Event const &)" (??0Event@Common@@$$FQAE@ABU01@@Z) CLRScumm D:\ScummVM\GIT\dists\CLRScumm\clr-events.obj 1
Error LNK2001 unresolved external symbol "public: virtual struct Graphics::Surface * __thiscall ModularBackend::lockScreen(void)" (?lockScreen@ModularBackend@@UAEPAUSurface@Graphics@@XZ) CLRScumm D:\ScummVM\GIT\dists\CLRScumm\OSystem_CLR.obj 1

Error LN

Thank you

[code]
ClrGraphics.cpp:
#include "clr-graphics.h"

CLRGraphicsManager::CLRGraphicsManager(CLREventSource* source) {

}

//CLRGraphicsManager::~CLRGraphicsManager() {
//}

void CLRGraphicsManager::activateManager() {

}

void CLRGraphicsManager::deactivateManager() {

}

//void CLRGraphicsManager::notifyResize(const int width, const int height) {
//
//}

bool CLRGraphicsManager::notifyMousePosition(Common::Point& mouse) {
return 0;
}

bool CLRGraphicsManager::showMouse(const bool visible) {
return 0;
}

bool CLRGraphicsManager::notifyEvent(const Common::Event& event) {
return 0;
}

void CLRGraphicsManager::copyRectToScreen(const void* buf, int pitch, int x, int y, int w, int h)
{
}
clrGraphics.h

//#ifndef BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H
//#define BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H

#include "backends/graphics/graphics.h"
#include "graphics/mode.h"

#include "common/events.h"
#include "common/rect.h"
#include "common/str.h"

class CLREventSource;

#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
#define USE_OSD 1
#endif

class CLRGraphicsManager : virtual public GraphicsManager, public Common::EventObserver {
public:
CLRGraphicsManager(CLREventSource* source);
virtual ~CLRGraphicsManager() {}

virtual void activateManager();


virtual void deactivateManager();
virtual void notifyVideoExpose() = 0;


virtual void notifyResize(const int width, const int height) {}


virtual bool notifyMousePosition(Common::Point& mouse);

virtual bool showMouse(const bool visible) override;

virtual bool saveScreenshot(const Common::String& filename) const { return false; }
//void saveScreenshot();

// Override from Common::EventObserver
virtual bool notifyEvent(const Common::Event& event) override;

virtual void copyRectToScreen(const void* buf, int pitch, int x, int y, int w, int h);

struct State {
int screenWidth, screenHeight;
bool aspectRatio;
bool fullscreen;
bool cursorPalette;

#ifdef USE_RGB_COLOR
Graphics::PixelFormat pixelFormat;
#endif
};


//bool setState(const State& state);

//virtual void initSizeHint(const Graphics::ModeList &modes) override;

protected:
virtual int getGraphicsModeScale(int mode) const = 0;

//bool defaultGraphicsModeConfig() const;
//int getGraphicsModeIdByName(const Common::String& name) const;

//void getWindowSizeFromSdl(int* width, int* height) const {
//}
};
OSystemCLR.cpp
#include "OSystem_CLR.h"

OSystem_CLR::OSystem_CLR() {

}
OSystem_CLR::~OSystem_CLR() {

}
void OSystem_CLR::init() {

}
void OSystem_CLR::initBackend() {

}
void OSystem_CLR::engineInit() {

}
void OSystem_CLR::engineDone() {

}
void OSystem_CLR::quit() {

}
void OSystem_CLR::fatalError() {

}
void OSystem_CLR::logMessage(LogMessageType::Type type, const char* message) {

}
Common::String OSystem_CLR::getSystemLanguage() const {
return 0;
}
uint32 OSystem_CLR::getMillis(bool skipRecord) {
return 0;
}
void OSystem_CLR::delayMillis(uint msecs) {

}
void OSystem_CLR::getTimeAndDate(TimeDate& td) const {

}
Audio::Mixer* OSystem_CLR::getMixer() {
return 0;
}
Common::TimerManager* OSystem_CLR::getTimerManager() {
return 0;
}
Common::SaveFileManager* OSystem_CLR::getSavefileManager() {
return 0;
}
Common::String OSystem_CLR::getScreenshotsPath() {
return 0;
}
AudioCDManager* OSystem_CLR::createAudioCDManager() {
return 0;
}
Common::WriteStream* OSystem_CLR::createLogFile() {
return 0;
}
const OSystem::GraphicsMode* OSystem_CLR::getSupportedGraphicsModes() const
{
return nullptr;
}
int OSystem_CLR::getDefaultGraphicsMode() const
{
return 0;
}
bool OSystem_CLR::setGraphicsMode(int mode)
{
return false;
}
int OSystem_CLR::getGraphicsMode() const
{
return 0;
}
char* OSystem_CLR::convertEncoding(const char* to, const char* from, const char* string, size_t length) {
return 0;
}
Common::String OSystem_CLR::getTextFromClipboard() {
return 0;
}
bool OSystem_CLR::setTextInClipboard(const Common::String& text) {
return 0;
}
void OSystem_CLR::setWindowCaption(const char* caption) {

}
void OSystem_CLR::addSysArchivesToSearchSet(Common::SearchSet& s, int priority) {

}
bool OSystem_CLR::hasFeature(OSystem::Feature f) {
return nullptr;
}

bool OSystem_CLR::hasTextInClipboard() {
return false;
}




int main(int argc, char* argv[])
{
}

OSystem_CLR.h:

#ifndef PLATFORM_SDL_H
#define PLATFORM_SDL_H


#include "backends/modular-backend.h"
#include "backends/log/log.h"


#include "common/array.h"
#include "common/system.h"
#include "common/scummsys.h"
#include "common/events.h"
#include "common/str.h"
#include "clr-events.h"

class OSystem_CLR : public ModularBackend {
public:
OSystem_CLR();
virtual ~OSystem_CLR();


virtual void init();


virtual bool hasFeature(Feature f);

// Override functions from ModularBackend and OSystem
virtual void initBackend();
virtual void engineInit();
virtual void engineDone();
virtual void quit();
virtual void fatalError();

// Logging
virtual void logMessage(LogMessageType::Type type, const char *message);

virtual Common::String getSystemLanguage() const;

// Clipboard

virtual Common::String getTextFromClipboard();
virtual bool setTextInClipboard(const Common::String &text);

virtual void setWindowCaption(const char *caption);
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
virtual uint32 getMillis(bool skipRecord = false);
virtual void delayMillis(uint msecs);
virtual void getTimeAndDate(TimeDate &td) const;
virtual Audio::Mixer *getMixer();
virtual Common::TimerManager *getTimerManager();
virtual Common::SaveFileManager *getSavefileManager();

//Screenshots
virtual Common::String getScreenshotsPath();

protected:
bool _inited;
bool _initedSDL;
#ifdef USE_SDL_NET
bool _initedSDLnet;
#endif
CLREventSource* _eventSource;

virtual Common::EventSource *getDefaultEventSource() { return _eventSource; }
virtual AudioCDManager *createAudioCDManager();

// Logging
virtual Common::String getDefaultLogFileName() { return Common::String(); }
virtual Common::WriteStream *createLogFile();
Backends::Log::Log *_logger;


int _desktopWidth, _desktopHeight;

typedef Common::Array<GraphicsMode> GraphicsModeArray;
GraphicsModeArray _graphicsModes;
Common::Array<int> _graphicsModeIds;
int _graphicsMode;
int _firstGLMode;
int _defaultSDLMode;
int _defaultGLMode;
//void setupGraphicsModes();

virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);
virtual int getGraphicsMode() const;

bool hasTextInClipboard();

protected:
virtual char *convertEncoding(const char *to, const char *from, const char *string, size_t length);
};

#endif


hey, welcome!
first, use code tags the <> in the side editor bar is the easy way to add them.
second, c++ errors propagate so usually the top 1-5 erros is all you care about when it spews. Fix and try again (unless its a billion lines of code and takes a day to compile, but presumably you are not on a gigantic project).

Next, the c++ string is string, and case matters. String is something else, a third party something, possibly a microsoftism. If you want to use whatever String is, you need to include a c++ file that defines it (.h header and .cpp) or a library or something. Its not part of the language. This could be <windows.h> in which case you need to be sure your project is set up to use the windows libraries.
string s; //c++, OK if you included <string>
String s; //not ok, third party!

It takes practice to read c++ errors. Once you 'get' it, you will see the madness in the method, but at first, it may as well be spouting in hieroglyphics.

Linker errors are not CODE errors, usually. They usually mean the code is OK but the project setup is borked. If it is a code error, it is usually a problem with a #include or misuse of a library.

This could be a chained problem. EG you download library X which needs Y which needs Z ... and so on... if something is missing it blows up. Microsoft has a binary examiner called 'depends.exe' that is part of visual studio and can help unravel these. Or you can read the docs on the libs one by one to see if they say what else you need. This process can be very painful.
Last edited on
Thanks :)
I will try the things you suggested and let you know how I went.
Thanks for your help.
I got past those linker errors, by adding an include reference to 'D:\ScummVM\GIT\common' which is an external SCUMM VM project I am referencing.

However now I seem to be having troubling with this compiler error.
Severity Code Description Project File Line Suppression State
Error C2039 'fabs': is not a member of '`global namespace'' CLRScumm C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\cstdlib 20

I found out that fabs is defined in corert_math.h which seems to be some sort of Microsoft mathematical library.

It is referenced by the Scumm VM project I just mentioned. This project compiles by itself so I am guessing I must be missing a reference to this external library in my project.

I guess this external Scumm VM project must be referencing it somehow, but I don't know how.

How would you generally go about referencing this library? Is there a visual studio project property I need to set?

I tried following the advice on this post: https://social.msdn.microsoft.com/Forums/vstudio/en-US/86bc577b-528c-469c-a506-15383a44c111/missing-corecrth-from-the-default-include-folder-for-vs215?forum=vcgeneral

ie: I used the 'additionalIncludeDirectory' property on my project, but it didn't make any difference.
Last edited on
I made a dumb mistake and had a typo in the folder. I will keep plowing on and let you know how I go.
Topic archived. No new replies allowed.