CopyFile Failing Dynamic Code Loading

I was going through the dynamic code loading episodes. Using the load counter seemed to work perfectly fine. However when I switched to using the last write time I get an issue where most of the time the CopyFile call fails. It sometimes doesn't however. Basically when I load up my program, try to change something and compile, it is completely random whether the CopyFile function fails. It could succeed the first time I try to recompile, or it could take like 7 times of me trying to recompile, and then work. I recently switched to a much faster machine, I don't remember having a problem on my old machine. I don't know if that has anything to do with it. I tried to use GetLastError to see how CopyFile is failing and it shows ERROR_SHARING_VIOLATION. I'm not sure if CompareFileTime somehow locks the file or if it's and issue with the FindFirstFile. I'm just clueless as to what is locking the file randomly.



The Code is being loaded in winmain like this its basically the way of day 22

FILETIME NewDLLWriteTime = Win32GetLastWriteTime(DllName);
if(CompareFileTime(&NewDLLWriteTime, &GameCode.DllLastWriteTime) != 0)
{
Win32UnloadGameCode(&GameCode);
GameCode = Win32LoadGameCode(DllName);

}

These are all the function calls

inline FILETIME Win32GetLastWriteTime(char* DllName)
{
FILETIME LastWriteTime = {};

WIN32_FIND_DATA FindData;
HANDLE FindHandle = FindFirstFileA(DllName, &FindData);
if(FindHandle != INVALID_HANDLE_VALUE)
{
LastWriteTime = FindData.ftLastWriteTime;
FindClose(FindHandle);
}
return LastWriteTime;

}

internal win32_game_code Win32LoadGameCode(char* DllName)
{
win32_game_code Result = {};

char* TempDLLName = "handmade_temp.dll";
Result.DllLastWriteTime = Win32GetLastWriteTime(DllName);
CopyFileA(DllName, TempDLLName, FALSE);
DWORD Error = GetLastError();
Result.GameCodeDLL = LoadLibraryA(TempDLLName);
Assert(Result.GameCodeDLL != NULL)
if(Result.GameCodeDLL)
{
Result.UpdateAndRender = (game_update_and_render*)GetProcAddress(Result.GameCodeDLL, "GameUpdateAndRender");
Result.GetSoundSamples = (game_get_sound_samples*)GetProcAddress(Result.GameCodeDLL, "GameGetSoundSamples");
Result.IsValid = (Result.UpdateAndRender && Result.GetSoundSamples);
}

if(!Result.IsValid)
{
Result.UpdateAndRender = GameUpdateAndRenderStub;
Result.GetSoundSamples = GameGetSoundSamplesStub;
}

return Result;

}

internal void Win32UnloadGameCode(win32_game_code* GameCode)
{
if(GameCode->GameCodeDLL)
{
Assert(FreeLibrary(GameCode->GameCodeDLL));
}

GameCode->IsValid = false;
GameCode->UpdateAndRender = GameUpdateAndRenderStub;
GameCode->GetSoundSamples = GameGetSoundSamplesStub;

}

Edited by Justin on Reason: Initial post
Hello Mouse,

I remember live code reloading caused several issues that were discussed several times on the Handmade Hero forums. In this one, GetLastError() returns the same error as it does for you: https://hero.handmade.network/for...yfile_and_comparefiletime_day_022
The solution for several peopel was to add a small delay before copying the file ( Sleep(250);) to make sure the compiler and/or you program doesn't use the dll anymore.

Weird bug with live code editing
Hot reloading problem sfml

When posting code, please use the code tags so the code is easier to read.
I just retry until it succeeds. I also do the same thing when deleting files on windows. The api is terribly unreliable.

Edit: The smartest thing would probably be to avoid the copy all together and load the dll into memory yourself and then inpsecting the pe to find the function pointers manually. It' a lot of work for something that easy, though. I still don't understand why we cannot load dll files from memory using a simple system call.

Edited by TheMole on
Hey guys, thanks for all the suggestions. So it seems the lock file solution from day 39, just before the Q&A, does the trick. I just hadn't got to that point yet. I think Casey was doing that because of pdb issues, but in this case I think it fixes my issue because it makes 100% sure that the dll is not locked by the compiler before doing the copy file call. So it was the compiler locking it, but if I tried to use something like Sleep() before the copy file, the only issue is the compile won't always take the same amount of time, so that would still sometimes not even work. This avoids having to know how long the compile takes which is nice.

Edited by Justin on Reason: Typo