1

Here's a scenario I'm exploring for a plugin framework:

A third party plugin developer designs a DLL with a known entry point and arbitrary parameters. They also provide details of the entry point and parameters in an XML file and provide data which they'll be called back with by my program when the plugin is invoked. They'll be alble to use a set of extensible variables in the XML which my program will expand and pass back to them through the parameters they specify.

I know that in win32 I can use LoadLibrary/GetProcAddress to get hold of the function they define. What I'm less clear about is whether I can dynamically generate a function specification from their defined parameters which I can use to call them back with. Anyone know if this is possible?

3 Answers 3

1

The c++ doesn't support reflection.

However, it is possible (up to some extend) by using the pococapsule library.


This article fully covers in details how to build a plugin framework.

Sign up to request clarification or add additional context in comments.

3 Comments

I wouldn't have thought that a full reflection API was necessary to dymically call a function if you know it's parameters. After all, in theory it'd be "easy" enough to do in assembler if you knew the calling convention (which I do). I'm just wondering if there's a good way to do this in standard c++. I guess I could just use a whole bunch of void * style functions and pick which one I needed then they'd have to cast the pointers back... but this seems a bit crap.
@Benj No, you do not need a full reflection. I might have misunderstood the question. The standard doesn't say how to load a library and use it's symbols (that is platform dependent). For that you do need to cast, because you can only access c functions
@Benj What you asked is super complex matter. I linked the article that can help you build a good plug in framework.
1

What I decided to do is to simply make the plugins accept a simple interface of:

DWORD func ( LPARAM pBuf, DWORD size );

This would allow the user to specify their parameters in the XML and then define a structure which they expect me to pass them, e.g.

typedef struct
{
    int a;
    float b;
    double c;
    wchar_t * d;
} test1;

When they get this message from me, they can check the size before using the buffer to ensure that the XML and the structure match.

As I parse the XML, I use this class with template methods to dynamically construct the object:

class DynamicStructure
{
public:

    template <typename T>
    void addField(const T & field)
    {
        m_mapPtrSize.push_back(std::make_pair(reinterpret_cast<const LPARAM>(&field), sizeof(T)));
    }

    DWORD getSize()
    {
        //
        // Work out the combined size of all the fields
        DWORD sSize = 0;
        for ( auto it = m_mapPtrSize.cbegin(); it != m_mapPtrSize.cend(); it++ )
        {
            sSize += it->second;
        }

        return sSize;
    }

    LPARAM getBuffer()
    {
        // Create a buffer big enough for all the fields
        //
        LPARAM pBuf = reinterpret_cast<LPARAM> (new (std::nothrow) BYTE[getSize()]);

        if (pBuf == NULL)
            return NULL;

        DWORD offset = 0;
        for ( auto it = m_mapPtrSize.cbegin(); it != m_mapPtrSize.cend(); it++ )
        {
            // Copy the fields one at a time, offsetting into the buffer
            //
            memcpy( (void*) (pBuf + offset), (const void*) it->first, it->second);
            offset += it->second;
        }

        return pBuf;
    }

protected:
private:
    std::vector<std::pair<const LPARAM, DWORD>> m_mapPtrSize;
};

This allows me to perform the following kind of operation as I parse the XML:

DynamicStructure dynStruct;
int a = 1;
float b = 2.3f;
double c = 3.5;
wchar_t * d = L"bob";

dynStruct.addField(a);
dynStruct.addField(b);
dynStruct.addField(c);
dynStruct.addField(d);

// Test - does the dymanic structure match the user's structure?
LPARAM pBuf = dynStruct.getBuffer();
test1 * pTest1 = (test1 *) pBuf;

std::wcout << pTest1->a << " " << pTest1->b << " " << pTest1->c << " " << pTest1->d << std::endl;

It's not perfect, and it's a bit old school, but at least it's simple and provides a reasonable level of safety.

Comments

0

you can't build functions at run-time, so you're left with compile-time options, like template meta-programming.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.