Handmade Hero»Forums»Code
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
If I expose a function returning a bool it will return a bool. If I call a function returning a float it will return a float.

I don't have to do any typedefs for the function pointer.
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
// the interface will look something like this:
struct MyDllInterface
{
virtual bool aFunction() = 0;
virtual float anotherFunction( int aValue ) = 0;
virtual float anotherFunction( int aValue, int anotherValue ) = 0;
};

// just call the functions

// on the dll side:

MyDllInterface* engineInterface;

// to call a function:

bool result = engineInterface->aFunction();

// the only thing that needs patching on load and reload is the engineInterface pointer
Mārtiņš Možeiko
2562 posts / 2 projects
Patching function pointers after dll reload?
Edited by Mārtiņš Možeiko on
So you want to write this?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
struct MyDllInterface
{
virtual bool aFunction() = 0;
};

struct MainMenu : MyDllInterface
{
virtual bool aFunction();
};

struct Gameplay : MyDllInterface
{
virtual bool aFunction();
};

struct Editor : MyDllInterface
{
virtual bool aFunction();
};

bool result = engineInterface->aFunction();


That's 21 line instead of 10. How that is far less code?

// the only thing that needs patching on load and reload is the engineInterface pointer
No, there are more pointers to patch - engineInterface pointer, engineInterface vtable and all function pointers in engineInterface vtable. Because after DLL is reloaded the vtable and ints contents can be located in different place. And patching vtable will need to be done in undocumented way, C++ standard doesn't specify how it is implemented.
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
Edited by Ritchie Brannan on Reason: Bad formatting of the quoted text
That's 21 line instead of 10. How that is far less code?

// the only thing that needs patching on load and reload is the engineInterface pointer

No, there are more pointers to patch - engineInterface pointer, engineInterface vtable and all function pointers in engineInterface vtable. Because after DLL is reloaded the vtable and ints contents can be located in different place. And patching vtable will need to be done in undocumented way, C++ standard doesn't specify how it is implemented.

Wow, that's pretty disingenuous.

There are so many things wrong with the way you have presented it that I am unsure where to begin explaining!

Firstly, you don't need the multiple structures inheriting from the interface, just 1 will do. Given that the rest of the code in HMH is pretty close to vanilla C, the functions in the inheriting class can simply call the C functions - effectively a pass through.

You don't need to patch the vtable at all, the DLL simply exposes a function which takes a void* to the interface supplied by the engine and does a reinterpret_cast on it. The vtable is in the engine memory area and doesn't need patching, the interface pointer actually points to it.

Where you might have a point with this regarding standards is if the engine and dll were compiled with different compilers.

So on DLL load, you patch the single function which takes the interface pointer, call that function passing the interface and after that all your calls from the dll to the engine go via the pointer.

To add a new function just add it to the interface and concrete implementation. If you don't mind being a bit more C++ you can implement the function directly in the concrete class rather than using this as a bridge to the C function.

The patch up code in both the DLL and engine is significantly smaller and adding new functions is trivial as among other reasons they don't need text signatures.
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
Obviously you can do this in both directions, exposing code in the DLL to the engine and vice-versa
Mārtiņš Možeiko
2562 posts / 2 projects
Patching function pointers after dll reload?
Edited by Mārtiņš Možeiko on
I'm not sure we are talking about same things.

OP asked how to patch his C++ pointers in inheritance he is doing. Everybody suggested to use C function pointers or switch statement, because it is simpler. But you insisted using C++ inheritance is far less code. Can you show how you would implement features OP wants with your approach? I don't see from your example how to do that with just one class (and far less code).
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
I read the OP question as one of fixing up function pointers. He also wanted a way of avoiding using a switch statement.

Using an interface allows him to trivially have whatever functions and as many functions as he wants and to switch them all simultaneously by simply changing the interface pointer.

Using an interface which only requires a single pointer to be patched is always going to be a lot less code than having to patch every function pointer.
Ritchie Brannan
11 posts
Patching function pointers after dll reload?
Edited by Ritchie Brannan on Reason: Clarity
Reading post #3250 by the OP, I'm not entirely clear what the OP is trying to achieve with the function patch up.

It looks like he has an issue with having function pointers in the game state that he would like to patch. At that point it is unclear to me whether these pointers would be into the DLL or Engine. Either could patch their own functions, though the DLL would need to be aware that either the game-state or DLL had been reloaded.
Jon Valdes
10 posts
Patching function pointers after dll reload?
Wow, relax, everyone! No need to fight over this :)

The functions are in the DLL, and I take function pointers to switch between the editor, gameplay, etc.

They're really just like the main "update and render" function in HH, but switchable depending on context. The problem is, when the DLL reloads, those pointers of course become invalid, and the game crashes.

Now, regarding ways to fix this, I think the second of Nimbal's solutions was pretty decent, without involving huge amounts of arcane magic.

My implementation looks like this:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
SCENE_UPDATE_FUNC(gameplayUpdateAndRender);
SCENE_UPDATE_FUNC(editorUpdateAndRender);
SCENE_UPDATE_FUNC(mainMenuUpdateAndRender);
SCENE_UPDATE_FUNC(settingsUpdateAndRender);

enum funcPointerNames{
    FUNC_GAMEPLAY_UPDATE,
    FUNC_EDITOR_UPDATE,
    FUNC_MAINMENU_UPDATE,
    FUNC_SETTINGS_UPDATE
};

typedef SCENE_UPDATE_FUNC((*gameSceneFunc));

global_var gameSceneFunc g_funcPointers[] = {
    gameplayUpdateAndRender,
    editorUpdateAndRender,
    mainMenuUpdateAndRender,
    settingsUpdateAndRender
};


Then in the data section I store an enum for the current scene, and then call it like this:
1
g_funcPointers[GameState->CurrentSceneFunc](MemPool, Platform, Renderer, Input, TimeInfo);


The dll, on load, makes sure the global function pointers array is initialized every time, so those pointers will never become invalid as long as I don't take them out of that array :)

This method has no switch statement, no class hierarchy, and is not very verbose. And if I ever need to use several types of functions, I can simply store them in an array of void(*)() pointers and cast them to the proper type before invocation.

Nice one, Nimbal :) Thanks!
Mārtiņš Možeiko
2562 posts / 2 projects
Patching function pointers after dll reload?
Edited by Mārtiņš Možeiko on
The dll, on load, makes sure the global function pointers array is initialized every time

You don't need to do that. Because g_funcPointers array is global in dll, it is reloaded together with function pointers. So it will still have correct values after reload (whatever compiler put there at compile time). No need to manually assign contents after dll reload.

And if I ever need to use several types of functions, I can simply store them in an array of void(*)() pointers and cast them to the proper type before invocation.
You can avoid casting and maintain type safety like this:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
typedef void FunctionPtrInt(int);
typedef void FunctionPtrFloat(float);

struct
{
  FunctionPtrInt* One;
  FunctionPtrFloat* Two;
}
static g_funcPointers[] =
{
  { gameplayOne, gameplayTwo },
  { editorOne,   editorTwo   },
  { mainMenuOne, mainMenuTwo },
};

g_funcPointers[GameState->CurrentSceneFunc].One(1);
g_funcPointers[GameState->CurrentSceneFunc].Two(2.0f);
Jon Valdes
10 posts
Patching function pointers after dll reload?
Oh, yes, I meant the dll init function does it automatically, I'm not doing anything manually :)
Casey Muratori
801 posts / 1 project
Casey Muratori is a programmer at Molly Rocket on the game 1935 and is the host of the educational programming series Handmade Hero.
Patching function pointers after dll reload?
jon_valdes
Well, it's just 1 line of code regardless of how many possible scenes you have. A switch statement grows with the number of functions.

Consider:
1
GameState->CurrentSceneFunc(MemPool, Platform, Renderer, Input, TimeInfo);


Versus:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SCENE_UPDATE_FUNC((*CurrentSceneFunc));
switch(GameState->CurrentScene){
case SceneMenu:
    CurrentSceneFunc = menuUpdateAndRender;
    break;
case SceneMainGameplay:
    CurrentSceneFunc = mainGameplayUpdateAndRender;
    break;
case SceneEditor:
    CurrentSceneFunc = editorUpdateAndRender;
    break;
[...]
}
CurrentSceneFunc(MemPool, Platform, Renderer, Input, TimeInfo);


It's not a hugely important thing, but it's something I'd like to avoid if possible.
Although from your responses so far I guess there isn't really much one can do in this case..


But you have written the switch case code wrong. It is actually less code to implement this in a switch statement, because you just put the code for each scene into the switch statement.

So you in fact save the entire preamble and postamble of all the functions you were writing if you use a switch, and you can also pull common code out more easily. Having it in multiple functions is more code, not less. And you no longer have to worry about keeping the function signatures consistent, or type-def'ing the function type.

- Casey
Jon Valdes
10 posts
Patching function pointers after dll reload?
You do have a point there. You can reuse code more easily with your method.

I guess your teachings of "don't pull stuff out into functions early" and the traditional "functions must be small and clean" mentality are still fighting inside my head...

I'll give it a try and see how it goes.
Thanks, Casey!
Casey Muratori
801 posts / 1 project
Casey Muratori is a programmer at Molly Rocket on the game 1935 and is the host of the educational programming series Handmade Hero.
Patching function pointers after dll reload?
Yeah. Keep in mind that neither way is "wrong", it's just that I wanted to make sure to point out that pretending there is an actual conciseness metric where switches cost more is not correct. You may still not like them for subjective reasons, but there is not an objective metric that makes them more unwieldy.

- Casey