Endauriel
Endauriel

Reputation: 432

Call a function in the main program from an imported DLL

I am trying to create a program that uses plugins in C++ to get some experience with importing and exporting functions from .dll and .so libraries. For simplicity's sake let's only use .dll libraries here.

What I'm trying to do is to make the communication between the plugin and the main program that loaded it "two-way", meaning the main program can call functions from the plugin (this is solved) and the plugin should be able to call functions from the main program (this I'm having trouble with).

I currently am able to create a .dll where I exported the functions with extern "C" {} and __declspec(export).

TestPlugin.h

#pragma once

extern "C" {
    __declspec(dllexport) const char* pluginName();
    __declspec(dllexport) void onLoad();
    __declspec(dllexport) void onShutdown();
}

TestPlugin.cpp

#include "TestPlugin.h"

#include <iostream>

const char * pluginName()
{
    return "Test Plugin";
}

void onLoad()
{
    std::cout << "onLoad() called!" << std::endl;
}

void onShutdown()
{
    std::cout << "onShutdown() called!" << std::endl;
}

I am then loading this test plugin with the following (shortened) code. I removed the error checking and console output.

Plugin.h

#pragma once

#include <filesystem>
#include <iostream>
#include <windows.h>

class Plugin
{
private:
    typedef const char*(*pluginNameType)();
    typedef void(*onLoadType)();
    typedef void(*onShutdownType)();

    HINSTANCE m_lib;
public:
    Plugin(std::filesystem::path filename);
    ~Plugin();

    pluginNameType pluginName;
    onLoadType onLoad;
    onShutdownType onShutdown;
};

Plugin.cpp

#include "Plugin.h"

Plugin::Plugin(std::filesystem::path filename)
{
    m_lib = LoadLibrary(filename.wstring().c_str());

    pluginName = (pluginNameType)GetProcAddress(m_lib, "pluginName");
    onLoad = (onLoadType)GetProcAddress(m_lib, "onLoad");
    onShutdown = (onShutdownType)GetProcAddress(m_lib, "onShutdown");
}

Plugin::~Plugin()
{
    FreeLibrary(m_lib);
}

What I can do now is to call the functions in the plugin (TestPlugin.cpp) from my main program.

main.cpp

Plugin *plugin = new Plugin("pathToDLLGoesHere");
plugin->onLoad();
plugin->onShutdown();

What I would like to do now is to also enable the test plugin I just loaded to have access to functions that are defined in the main program. So let's say in my main.cpp I have something like this ...

main.cpp

int testCall(int val) {
    return val + 1;
}

int main()
{
    ...

    return 0;
}

... how would I be able to call the testCall() from the test plugin?

Would it be as simple as to send the function pointer to the plugin and use it? Or do I need to take a different approach here? Thank you for your help!

Upvotes: 1

Views: 1759

Answers (1)

Endauriel
Endauriel

Reputation: 432

I have figured out how this works. You can also use extern "C" {} and __declspec(dllexport) to export functions from your main program so the DLLs can see them and when you get the handle of your main program in the DLL, the functions can be called.

In one of your headers in your main program you export the function.

main.h

extern "C" {
    __declspec(dllexport) int testCall(int val);
}

main.cpp

int testCall(int val) {
    return val + 1;
}

In my test plugin header I created a handle for the main program and a definition for the function I am trying to call from main.

TestPlugin.h

#pragma once

#include <windows.h>

HINSTANCE app;
int(*testCall)(int val);

...

In the body I then assign the handle (calling GetModuleHandle with a nullptr will give you the handle of your program) and then get the exported function from my main program.

TestPlugin.cpp

app = GetModuleHandle(nullptr);
testCall = (int(*)(int val))GetProcAddress(app, "testCall");

After that, I can just call the function.

std::cout << testCall(5) << std::endl;

result

Upvotes: 1

Related Questions