0

I have a problem using cereal with dynamic libraries on Windows (DLLs). I have read the documentation on the cereal site. However, all documentation and examples implicitly link DLLs, while I need to be able to explicitly link my DLLs. I made an example project to show you my setup and where I get stuck.

The project is divided into three projects, 2 DLLs and an executable. The first DLL (Object.dll) contains a Base class called Object. This DLL is implicitly linked to the second DLL (Script.dll), which implements a Derived class called Script. This DLL is then explicitly linked into the executable (Main.exe).

Object.dll:

Object.h

#pragma once

class __declspec(dllexport) Object
{
public:
    Object();
    virtual ~Object();

    int so;
    virtual void foo() = 0;

    template<class Archive>
    void serialize(Archive& ar)
    {
        ar(so);
    }
};

Object.cpp is empty, so I've omitted it.

Script.dll:

Script.h

#pragma once
#include "Object.h"

class Script : public Object
{
public:
    Script();
    ~Script();

    void foo() override;

    template<class Archive>
    void serialize(Archive& ar)
    {
        ar(cereal::base_class<Object>(this));
    }
};

Script.cpp

#include "Script.h"

Script::Script()
{
}


Script::~Script()
{
}

void Script::foo()
{
}

extern "C" __declspec(dllexport) Object* CreateObject()
{
    return new Script();
}

extern "C" __declspec(dllexport) void DeleteObject(Object* obj)
{
    delete obj;
    obj = nullptr;
}

Main.exe

#include "Object.h"
#include "Windows.h"

#include "cereal/archives/xml.hpp"
#include "cereal/types/memory.hpp"



typedef Object* (__cdecl *CREATEFUNCTION)();
typedef void(__cdecl *DELTEFUNCTION)(Object*);

using namespace std;

int main()
{
    std::string dll("DLL.dll");
    HINSTANCE dllHandle = LoadLibraryA(dll.c_str());
    if (dllHandle == nullptr)
    {
        cout << "Couldn't load the DLL of the script " << endl;
        return 1;
    }

    CREATEFUNCTION CreateObject = reinterpret_cast<CREATEFUNCTION>(GetProcAddress(dllHandle, "CreateObject"));
    if (CreateObject == nullptr)
    {
         cout << "Couldn't load the CreateObject() function" << endl;
         return 1;
    }

    DELTEFUNCTION DeleteObject = reinterpret_cast<DELTEFUNCTION>(GetProcAddress(dllHandle, "DeleteObject"));
    if (DeleteObject == nullptr)
    {
        cout << "Couldn't load the DeleteObject() function" << endl;
        return 1;
    }

    std::shared_ptr<Object> obj = std::shared_ptr<Object>(CreateObject(), DeleteObject);

    cereal::XMLOutputArchive oAr(std::cout);
    oAr(obj);

    return 0;
}

Of course, at the moment it throws the exception UNREGISTERED_POLYMORPHIC_EXCEPTION, because I don't register my Script class. And this is also my issue, according to what I have read, I should add the macro CEREAL_REGISTER_DYNAMIC_INIT to the source file where I call CEREAL_REGISTER_TYPE, which would be the Script.h file because I can't add it to the source file according to the Polymorphism documentation. I should also add CEREAL_FORCE_DYNAMIC_INIT to the header that gets included in the main application, but I don't include the Script.h file anywhere.

I have tried to put each macro in various places (without including it in the main.exe), but I have not got it to work. Does anybody know where these two function should go so that I can register my Script class and call its serialize function?

resul4e
  • 1
  • 3
  • Unless you used a .def file, these function names are not actually "CreateObject" and "DeleteObject". We don't know what DLL_API does so you'll have to take a look-see yourself. Use the linker's .map file or use Dumpbin.exe /exports to see the real names. Do focus on generating a better exception or error message and don't just keep going blindly when GetProcAddress returns NULL. – Hans Passant Oct 10 '17 at 17:06
  • Hey, I define DLL_API to be __declspec(dllexport) combined with the extern "C" the names most definitely not be mangled. This was an example project where I knew that all of these functions would be present which is why I didn't add any checking. However, thank you I'll make the changes so that others don't get confused. – resul4e Oct 10 '17 at 17:17
  • They are decorated, not mangled. The default for cdecl in 32-bit code is a leading underscore. – Hans Passant Oct 10 '17 at 17:19
  • Ah thought they were mangled, thanks for the info. – resul4e Oct 10 '17 at 17:49

0 Answers0