0

I have a DLL that gets loaded as a plugin by a program I did not create and it's purpose is to replace a pointer to a member function in an array inside the program to provide additional functionality to the existing program that loads it.

The program (that loads the plugin dll) has source code that looks like this

//Core object that all objects inherit
class MObject
{
public:
    //variables

    //functions
}

enum ECmdIndex
{
    CMD_RUN = 0x0,
    //ect
    CMD_MAX = 0x500
}
//Global command list of command functions
typedef void (MObject::*CommandFunc)(SContext&, void*)
CommandFunc GCommands[CMD_MAX];

//Example command function
void MObject::funcCmdRun(SContext& context, void* result)
{
    //do stuff
}
GCommands[CMD_RUN] = &MObject::funcCmdRun;

//This is used to execute command functions
void MObject::ProcessCommand( SContext& context, void* result )
{
    //ect

    //Execute the command's function on this MObject
    //Here is where my function should replace the default one
    (this->*GCommands[context.cmdInd])(context, result);

    //ect
}

My DLL is fairly straight forward. It mainly replaces a command function in the program's GCommands array with one in the DLL.

//MObject structure is replicated exactly in the DLL
//This is neccesary because my plugin is going beyond the provided API
//And so this is becoming a bit "hacky"
class MObject
{
public:
    //variables

    //functions
}

typedef void (MObject::*CommandFunc)(SContext&, void*)

void MObject::MyCommandFunc(SContext& context, void* result)
{
    //do stuff
}

void onLoad()
{
    //Get a pointer to GCommands array
    CommandFunc** pGCommands = GetGCommandOffset();

    //Replaced the desired command function with the new one
    pGCommand[0x1B] = &MObject::MyCommandFunc;
}

A brief abstract: The host program calls a member function pointer. My DLL should make the pointer point to its own function and do what is must to make that function callable when the host application goes to call that pointer.

The issue is my new command function is never entered and the command no longer does anything when executed in the program. I would at the very least expect a crash. I apologize for the inherent hacky appearance of the code but surely there is a correct way to accomplish this?

Slight
  • 1,541
  • 3
  • 19
  • 38
  • As a side note I've found questions like [this one](http://stackoverflow.com/questions/1307278/casting-between-void-and-a-pointer-to-member-function) helpful as well as the links contained within. Ultimately they haven't been enough to solve my issue. – Slight Jun 10 '13 at 12:34
  • I think you are going to have big issues with redefining an object used across the DLL boundary! That should be defined in either a common lib or a common header. What are you trying to accomplish and is there any reason why you have to stick with this design? – Dennis Jun 10 '13 at 12:45
  • Unfortunately I am stuck with this method as the MObject class is not exposed at all and is used internally only. The plugin API is still young and doesn't provide much functionality or flexibility. – Slight Jun 10 '13 at 12:51

1 Answers1

1

The root cause here seems to be an ODR violation. Your host app defines a MObject with one implementation of MyCommandFunc (or no implementation at all), and your DLL defines it with another. What you're trying to do here (override class functionality on a per-member-function basis, via an array of function pointers) is weird as heck, and is never going to work even close to portably.

If you have a bunch of commands which operate on an MObject, you can just declare them as nonmember (or static member) functions which take an MObject, and have an array of those. (You could instead expose them as implementations of a MObjectCommand virtual interface, but it doesn't look like you need any state so that's probably unnecessary.)

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • You may have misinterpreted the question a bit. I have no control over the code of the host application as it was not written by me. I am writing a DLL which is loaded by the host application which is then modifying a pointer in the host application to point to my function. The problem is how to I get my function to be called properly by the host program. If this were a regular function pointer there would be no problem. Also, if I must __declspec(naked) my function and write prolog asm myself I would do if it was an issue on the callee's side. – Slight Jun 10 '13 at 12:57