Files
Ben Marsh e1fe0cc030 Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.

Changes vs standalone Live++ version:

* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.

Known issues:

* Does not currently support class layout changes / object reinstancing

#rb none
#fyi Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira

[CL 5304722 by Ben Marsh in 4.22 branch]
2019-03-05 15:54:02 -05:00

137 lines
3.5 KiB
C++

// Copyright 2011-2019 Molecular Matters GmbH, all rights reserved.
#pragma once
#include "CoreTypes.h"
#include "LC_Thread.h"
#include <string>
#include <vector>
namespace process
{
struct Context
{
uint32_t flags;
HANDLE pipeReadEnd;
PROCESS_INFORMATION pi;
thread::Handle threadId;
std::wstring stdoutData;
};
struct Module
{
std::wstring fullPath;
void* baseAddress;
uint32_t sizeOfImage;
};
typedef HANDLE Handle;
// returns the process ID for the calling process
unsigned int GetId(void);
struct SpawnFlags
{
enum Enum : uint32_t
{
NONE = 0u,
REDIRECT_STDOUT = 1u << 0u
};
};
// spawns a new process
Context* Spawn(const wchar_t* exePath, const wchar_t* workingDirectory, const wchar_t* commandLine, const void* environmentBlock, uint32_t flags);
// waits until a spawned process has exited
unsigned int Wait(Context* context);
// destroys a spawned process
void Destroy(Context*& context);
// terminates a spawned process
void Terminate(Handle processHandle);
// opens a process
Handle Open(unsigned int processId);
// closes a process
void Close(Handle& handle);
// returns the full path for a process' image
std::wstring GetImagePath(Handle handle);
// returns the base address of the calling process
void* GetBase(void);
// returns the path to the executable of the calling process
std::wstring GetImagePath(void);
// returns the size of a module loaded into the virtual address space of a given process
uint32_t GetImageSize(Handle handle, void* moduleBase);
// returns whether the process with the given handle is still active
bool IsActive(Handle handle);
// reads from process memory
void ReadProcessMemory(Handle handle, const void* srcAddress, void* destBuffer, size_t size);
template <typename T>
T ReadProcessMemory(Handle handle, const void* srcAddress)
{
T value = {};
ReadProcessMemory(handle, srcAddress, &value, sizeof(T));
return value;
}
// writes to process memory
void WriteProcessMemory(Handle handle, void* destAddress, const void* srcBuffer, size_t size);
template <typename T>
void WriteProcessMemory(Handle handle, void* destAddress, const T& value)
{
WriteProcessMemory(handle, destAddress, &value, sizeof(T));
}
// scans a region of memory in the given process until a free block of a given size is found.
// will only consider blocks at addresses with a certain alignment.
void* ScanMemoryRange(Handle handle, const void* lowerBound, const void* upperBound, size_t size, size_t alignment);
// makes the memory pages in the given region executable (in case they aren't already) while keeping other protection flags intact
void MakePagesExecutable(Handle handle, void* address, size_t size);
// flushes the process' instruction cache
void FlushInstructionCache(Handle handle, void* address, size_t size);
// suspends a process
void Suspend(Handle handle);
// resumes a suspended process
void Resume(Handle handle);
// continues the calling thread of a process with the given thread context
void Continue(CONTEXT* threadContext);
// enumerates all threads of a process, returning their thread IDs.
// NOTE: only call on suspended processes!
std::vector<unsigned int> EnumerateThreads(unsigned int processId);
// enumerates all modules of a process, returning their info.
// NOTE: only call on suspended processes!
std::vector<Module> EnumerateModules(Handle handle);
// dumps raw memory for a given process
void DumpMemory(Handle handle, const void* address, size_t size);
}