hot reloading problem (SFML)

When I change some attributes in the gameCode.cpp it does seem to succesfully reload the DLL during runtime
however, i don't see the changes on screen, that was made in the code.
I want it to reload during runtime.

If i restart the app the changes work, so the problem is just that it doesn't reload during runtime.

I am also using a 3rd party lib (SFML)

any ideas why this problem might occur?

CJsfml_002.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define SFML_STATIC 
#define WIN32_LEAN_AND_MEAN 

#include <windows.h>
#include "SFML\Graphics.hpp" 

#include <iostream>

float vel = 7.0f;

typedef void (*rectFP)(sf::RectangleShape *);

int main() 
{
	sf::RenderWindow window(sf::VideoMode(960, 540), "SFML works!"); 
	window.setFramerateLimit(60);	
	
	sf::RectangleShape mRect(sf::Vector2f(40.0f, 40.0f));;
	mRect.setPosition(sf::Vector2f(30.0f, 30.0f));	
	mRect.setFillColor(sf::Color::Green);

        // Getting pointer to the rect
	sf::RectangleShape *rect = &mRect;


	while (window.isOpen())
    {
		int count = 125;
                
               // Loading DLL
		CopyFile("gameCode.dll", "temp_gameCode.dll", false);
		HMODULE hm = LoadLibrary("temp_gameCode.dll");

		if(hm)
		{
				std::cout << "LOAD LIB SUCCESS!\n";
		}
                
               // Loading DLL function
		rectFP rfp = (rectFP)GetProcAddress(hm, "CreateRect");

		if(rfp)
		{
				std::cout << "load func SUCCESS!\n";
		}


                // Using the DLL function
		rfp(rect);		}

               // Unloads DLL
		FreeLibrary(hm);
		


        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        
        // Drawing the rect that was changed by the DLL-function
	window.draw(*rect);

        window.display();

    }

    return 0;
}


gameCode.h
1
2
3
4
5
6
7
#define SFML_STATIC
#include "SFML\Graphics.hpp"

extern "C"
{
	__declspec(dllexport) void CreateRect(sf::RectangleShape *RS);
}	


gameCode.cpp
1
2
3
4
5
6
7
8
#include "gameCode.h"

__declspec(dllexport) void CreateRect(sf::RectangleShape *RS)
{
	RS->setSize(sf::Vector2f(100.0f, 200.0f));	
	RS->setFillColor(sf::Color::Blue);
	RS->setPosition(sf::Vector2f(100.0f, 100.0f));
}


build.bat
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@echo off

:: IMPORTANT!  "=" has to come IMMEDIATLEY after VARIABLE NAME

SET compilerSwitches= /MD /EHsc -Zi -nologo 
SET winLibs= user32.lib gdi32.lib winmm.lib Opengl32.lib ws2_32.lib advapi32.lib

SET sfmlDependLibsX64= /LIBPATH:"C:\SFML\SFML-2.5.1_x64\lib" freetype.lib openal32.lib flac.lib vorbisenc.lib vorbisfile.lib vorbis.lib ogg.lib
SET sfmlDependLibsX86= /LIBPATH:"C:\SFML\SFML-2.5.1_x86\lib" freetype.lib openal32.lib flac.lib vorbisenc.lib vorbisfile.lib vorbis.lib ogg.lib

SET sfmlLibsX64= sfml-system-s.lib sfml-graphics-s.lib sfml-window-s.lib sfml-audio-s.lib sfml-network-s.lib
SET sfmlLibsX86= sfml-system-s.lib sfml-graphics-s.lib sfml-window-s.lib sfml-audio-s.lib sfml-network-s.lib

If NOT EXIST ..\buildx64 mkdir ..\buildx64
If NOT EXIST ..\buildx86 mkdir ..\buildx86
If NOT EXIST ..\assets mkdir ..\assets

 pushd ..\buildx64
 
 cl %compilerSwitches% /I ..\include ..\src\CJsfml_002.cpp %winLibs% /link %sfmlDependLibsX64% %sfmlLibsX64%
 cl %compilerSwitches% /I ..\include ..\src\gameCode.cpp /LD %winLibs% /link %sfmlDependLibsX64% %sfmlLibsX64%
 
 popd
 
 @echo x64 build Done!
 
 ::------------------ x86 BUILD (set vcvarsx86) -----------------

 ::pushd ..\buildx86
  
 ::cl /MD /EHsc -Zi -nologo /I ..\include ..\src\CJsfml_002.cpp %winLibs% /link %sfmlDependLibsX86% %sfmlLibsX86%
  
 ::popd
 ::
 ::@echo x86 build Done!

del *.~ *.cpp~ *.bat~ *.un~ *.h~

Edited by C_Worm on
Without the full source it's hard to help you. And the code you posted isn't nested properly.

Are you sure the new dll is copied by CopyFile ? Are you sure the new dll is loaded properly ? Did you try to step in the dll function to see if it's executing the correct code after reloading ? Is rect containing the right values after the call ?
Are you sure call to cl.exe to compile gameCode.dll succeeds? Because it could fail if that happens at same time when CopyFile function is being executed. Verify that cl.exe really succeeds.

Try putting brakpoint on "rfp(rect);" line and do "step in" in the debugger. If dll is rebuild correctly and pdb files are not corrupted you'll be able to step into new code.

Also - you really should be linking to sfml dynamically (dll files), not statically. Because you are using SFML in main exe and in dll as separate copies, but you are passing objects across dll boundaries. This means that some code for objects is called in main .exe but other code for same objects is called in .dll. Depending on situation this may or may not work. Most likely you will get strange crashes later when you'll have a bit more complex code.

Edited by Mārtiņš Možeiko on
The CopyFile fails with error code 32 (ERROR_ACCESS_VIOLATION).

The first time it calls CopyFile it works, but all times after that it doesn't, becuase im getting access violation, any ideas on how to solve it?

And I am able to step through the rfp(rect) function in the dbugger unless I recompile during runtime.

Edited by C_Worm on
Either you're copying the source dll while MSVC is writing to it, or you are overwriting "temp_gameCode.dll" while your program still uses it.

After you free the library it may take some time for the file to be released (maybe the debugger also has a handle to the file). Adding Sleep( 250 ); to wait 250 ms before trying to copy the dll worked on a quick test on my machine, but that wouldn't give you a nice frame rate. You should probably only reload the dll when a new one has been compiled.

In handmade hero, Casey does several things to try to avoid problems:
- reload the dll only when it was recompiled, not every frame;
- copy the dll to a different name every time (name_0001.dll, adding 1 each time);
- after freeing the dll, it tries to load the new one (copy the file + load). If it fails (either the copy or load) it wait 100 ms and try again, up to 100 times).
Oh gosh!

The problem all along was that I compiled the dll and exe in the wrong order(exe first, then dll), now it seems to work fine!

Thanks
I doubt that was the cause of the problem. Compiling the exe should fail when you're running the exe because the compiler will not be able to overwrite the file.
Yes compiling the exe is failing during runtime but compiling the dll works which contains the gamecode changes, and that is what i was trying to achieve i think ^^.

But i still have to but sleep before copyfile.

So now im off to check lastwrite time and all that to copy/load the dll only when it is compiled and then get the instantaneous loading.

Edited by C_Worm on