Live++ integration

Live++ is a generic hot reload solution for C++ applications. D0 requires the following integration to work correctly:

1. Copy & paste this code just below your #include "LPP_API_x64_CPP.h" include (note: you may need to include Windows.h if it is not already).
LPP_NAMESPACE_BEGIN
static bool   s_agentRunning = true;
static HANDLE s_agentThread = 0;
DWORD WINAPI D0_LivePPAgentThread(LPVOID param)
{
    LppSynchronizedAgent*    agent     = (LppSynchronizedAgent*)param;
    const LppReloadOption    option    = LPP_RELOAD_OPTION_SYNCHRONIZE_WITH_COMPILATION_AND_RELOAD;
    const LppReloadBehaviour behaviour = LPP_RELOAD_BEHAVIOUR_WAIT_UNTIL_CHANGES_ARE_APPLIED;
    bool firstReload = true;
    while (s_agentRunning) {
        if (agent->WantsReload(option)) {
            agent->Reload(behaviour);
            if (firstReload) {
                agent->EnableModule(LppGetCurrentModulePath(), LPP_MODULES_OPTION_ALL_IMPORT_MODULES, 0, 0);
                while (!agent->WantsReload(option)) {
                    agent->ScheduleReload();
                    Sleep(30);
                }

                agent->Reload(behaviour);
                firstReload = false;
            }
        }

        Sleep(10);
    }

    return 0;
}

bool D0_StartSynchronizedAgentWithPreferences(LppSynchronizedAgent* agent, const LppLocalPreferences* localPrefs, const wchar_t* absoluteOrRelativePathWithoutSlash, const LppProjectPreferences* prefs)
{
    LppProjectPreferences fixedPrefs = prefs ? *prefs : LppCreateDefaultProjectPreferences();
    fixedPrefs.exceptionHandler.order = 0;
    *agent = LppCreateSynchronizedAgentWithPreferences(localPrefs, absoluteOrRelativePathWithoutSlash, &fixedPrefs);
    s_agentThread = CreateThread(0, 0, &D0_LivePPAgentThread, agent, 0, 0);
    return LppIsValidSynchronizedAgent(agent) && s_agentThread != 0;
}

void D0_DestroySynchronizedAgent(LppSynchronizedAgent* agent)
{
    s_agentRunning = false;
    WaitForSingleObject(s_agentThread, INFINITE);
    LppDestroySynchronizedAgent(agent);
}
LPP_NAMESPACE_END

2. Replace your existing agent initialization code with the call to new code:
lpp::LppSynchronizedAgent agent;
lpp::D0_StartSynchronizedAgentWithPreferences(&agent, NULL, absoluteOrRelativePathWithoutSlash, NULL);

Where absoluteOrRelativePathWithoutSlash is the same path you used in your existing code.


3. Destroy the agent when the application is closing:
lpp::D0_DestroySynchronizedAgent(&agent);

Why is this required?
There are two issues that are present when starting debugging with Live++ and D0:
  • Live++ will catch exceptions that need to be handled by D0 first. This is fixed by adding exceptionHandler.order = 0; to the agent preferences.
  • Live++ allocates pretty much all memory around your code to load new patches close enough to the original code. If this happens before the debugger attaches, D0 will not be able to use any of that space for its own patches. This is fixed by moving the agent EnableModule call to when the first reload is requested. This provides enough time for D0 to initialize and obtain some memory for its relocations.

If you have any issues with D0 or the integration, you can talk to me directly on Discord: