UniversalOverlay is a C++23 static library for injected Win32 overlays. It hooks the target renderer, starts Dear ImGui, routes input, draws your menu/windows, persists settings, and unloads cleanly.
Use it when you want a debugging menu, SDK inspection panel, cheat menu, entity viewer, live diagnostics window, or always-on overlay without rebuilding renderer hooks and ImGui plumbing for every project.
Read the docs: malkahservices.ca/UniversalOverlay
Choose the renderer used by the target process, pass it to Initialize(), then build/reload your host DLL.
| Target renderer | Use this enum | Hook path |
|---|---|---|
| Direct3D 11 | GraphicsAPI::D3D11 |
IDXGISwapChain::Present and ResizeBuffers |
| Direct3D 12 | GraphicsAPI::D3D12 |
Present, ResizeBuffers, and command queue ExecuteCommandLists |
| Direct3D 9 | GraphicsAPI::D3D9 |
IDirect3DDevice9::EndScene and Reset |
| OpenGL 3 | GraphicsAPI::OpenGL3 |
wglSwapBuffers |
UniversalOverlay::Initialize(UniversalOverlay::GraphicsAPI::D3D11);Only initialize one renderer per overlay lifetime. If you need runtime selection, decide before Initialize():
UniversalOverlay::GraphicsAPI api = UniversalOverlay::GraphicsAPI::D3D11;
if (useD3D12)
api = UniversalOverlay::GraphicsAPI::D3D12;
else if (useD3D9)
api = UniversalOverlay::GraphicsAPI::D3D9;
else if (useOpenGL)
api = UniversalOverlay::GraphicsAPI::OpenGL3;
if (!UniversalOverlay::Initialize(api))
return;- Open
UniversalOverlay.slnin Visual Studio 2022. - Build
DebugorReleaseforx86orx64. - Link your injected DLL against:
Build/[Configuration]/[Platform]/UniversalOverlay.lib
In your DLL project:
- Add include dirs:
Src/,External/ImGui,External/ImGui/Backends,External/MinHook/include. - Link the matching
libMinHook.x86.liborlibMinHook.x64.lib. - Use C++23 (
/std:c++23). - Include
UniversalOverlay.handimgui.h.
Copy this into your injected DLL project, then change the GraphicsAPI enum for the target renderer.
#include <Windows.h>
#include <cstdio>
#include <filesystem>
#include <string>
#include "UniversalOverlay.h"
#include "imgui.h"
namespace
{
bool g_enabled = true;
float g_alpha = 0.85f;
int g_mode = 1;
std::wstring GetConfigPath(HMODULE module)
{
wchar_t modulePath[MAX_PATH] = {};
const DWORD length = GetModuleFileNameW(module, modulePath, MAX_PATH);
if (length == 0)
return L".\\UniversalOverlaySettings.ini";
return (std::filesystem::path(modulePath).parent_path() / L"UniversalOverlaySettings.ini").wstring();
}
void DrawExampleSettings()
{
bool changed = false;
changed |= ImGui::Checkbox("Enabled", &g_enabled);
changed |= ImGui::SliderFloat("Overlay alpha", &g_alpha, 0.10f, 1.0f, "%.2f");
changed |= ImGui::Combo("Mode", &g_mode, "Idle\0Tracking\0Warning\0\0");
if (changed)
UniversalOverlay::MarkConfigDirty();
}
void DrawExampleTab()
{
ImGui::TextUnformatted("UniversalOverlay starter");
DrawExampleSettings();
if (ImGui::Button("Open status window"))
UniversalOverlay::SetFloatingWindowOpen("Example Status", true);
if (ImGui::Button("Save preset 1"))
UniversalOverlay::SaveConfigPreset(1);
ImGui::SameLine();
if (ImGui::Button("Load preset 1"))
UniversalOverlay::LoadConfigPreset(1);
}
void DrawExampleWindow(bool menuOpen)
{
ImGui::Text("Mode: %d", g_mode);
if (menuOpen)
DrawExampleSettings();
}
void DrawExampleOverlay()
{
if (!g_enabled)
return;
char label[64] = {};
sprintf_s(label, "UniversalOverlay alpha %.2f", g_alpha);
ImGui::GetBackgroundDrawList()->AddText(
ImVec2(20.0f, 20.0f),
IM_COL32(80, 220, 255, static_cast<int>(255.0f * g_alpha)),
label);
}
DWORD WINAPI OverlayThread(LPVOID parameter)
{
HMODULE module = static_cast<HMODULE>(parameter);
const std::wstring configPath = GetConfigPath(module);
if (!UniversalOverlay::Initialize(UniversalOverlay::GraphicsAPI::D3D11))
FreeLibraryAndExitThread(module, 0);
UniversalOverlay::SetMenuDefaultSize(980.0f, 640.0f);
UniversalOverlay::RegisterConfigBool("Example", "Enabled", &g_enabled);
UniversalOverlay::RegisterConfigFloat("Example", "Alpha", &g_alpha, 0.85f);
UniversalOverlay::RegisterConfigInt("Example", "Mode", &g_mode, 1);
UniversalOverlay::LoadConfig(configPath);
UniversalOverlay::RegisterSettingsSection("Example", DrawExampleSettings);
UniversalOverlay::RegisterTab("Example", DrawExampleTab);
UniversalOverlay::RegisterFloatingWindow("Example Status", DrawExampleWindow, true, false, 0.55f);
UniversalOverlay::RegisterRenderCallback(DrawExampleOverlay);
while (!UniversalOverlay::ShouldUnload())
Sleep(100);
UniversalOverlay::SaveConfig(configPath);
UniversalOverlay::Shutdown();
FreeLibraryAndExitThread(module, 0);
return 0;
}
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID)
{
if (reason != DLL_PROCESS_ATTACH)
return TRUE;
DisableThreadLibraryCalls(module);
HANDLE thread = CreateThread(nullptr, 0, OverlayThread, module, 0, nullptr);
if (thread)
CloseHandle(thread);
return TRUE;
}- Renderer hooks: OpenGL 3, Direct3D 9, Direct3D 11, and Direct3D 12.
- Menu extension: register tabs with
RegisterTab()and Settings sections withRegisterSettingsSection(). - Per-frame drawing: use
RegisterRenderCallback()for labels, boxes, meters, crosshairs, and drawlist work. - Floating windows: use
RegisterFloatingWindow()for inspectors, watch lists, logs, or pinned utility windows. - Settings and presets: register
bool,float,int, anduint64_tvalues, thenLoadConfig(),SaveConfig(),SaveConfigPreset(), andLoadConfigPreset(). - Fonts and icons: built-in vector fonts, Font Awesome icon glyphs, plus custom file or memory fonts with
RegisterFont(),SetSelectedFont(), andGetSelectedFontId(). - Theming: built-in
Themessurface, theme tokens, compact layouts, status pills, badges, meters, and draw helpers. - Input and cursor handling: hooked
WndProcinput routing while the menu is open, with cursor-lock handoff. - Diagnostics: rotating logs under
%TEMP%\UniversalOverlay\<process-id>\throughExternal/spdlog; debug builds include richer diagnostics surfaces. - Safe unload:
RequestUnload()andShouldUnload()let your host thread save config, shut down hooks, and exit cleanly.
- Register config values before
LoadConfig(). - Call
MarkConfigDirty()after an ImGui control changes a registered value. RegisterRenderCallback()runs while the overlay is active, even when the menu is closed.RegisterTab()callbacks run while the menu is open and the tab is selected.- Unpinned floating windows show while the menu is open; pinned windows can stay visible after it closes.
- Default hotkeys are
.for menu toggle andF1for unload.
Initialize(GraphicsAPI api)/Shutdown()ShouldUnload()/RequestUnload()IsMenuOpen()/SetMenuOpen(bool open)SetMenuDefaultSize(float width, float height)RegisterTab(name, callback)RegisterSettingsSection(name, callback)RegisterRenderCallback(callback)RegisterFloatingWindow(name, callback, defaultOpen, defaultPinned, backgroundAlpha)SetFloatingWindowOpen(name, open)/SetFloatingWindowPinned(name, pinned)RegisterFont(spec)/SetSelectedFont(id)/GetSelectedFontId()RegisterConfigBool/Float/Int(section, key, pointer, defaultValue)LoadConfig(path)/SaveConfig(path)SaveConfigPreset(slot)/LoadConfigPreset(slot)
The full Doxygen site is published automatically:
Open the UniversalOverlay documentation
- Users do not need to install Doxygen or generate docs locally.
- Source pages start at
docs/doxygen/pages/mainpage.md. - GitHub Actions builds the site from
productionand publishes it with GitHub Pages. - Generated HTML stays out of git under
docs/doxygen/html/.
Most users only need Src/UniversalOverlay.h.
Useful internals:
- Core/config/logging:
Src/Core/UniversalOverlayCore.cpp,ConfigSystem.h/cpp,OverlayLog.h/cpp; logging usesExternal/spdlog. - Renderer hooks/backends:
Src/Hooks/Hooks.h/cpp,WndProcHook.h/cpp,CursorHook.h/cpp,Src/Renderer/Renderer.h/cpp,RendererTypes.h, andRenderer/Backends. - UI shell/helpers:
Menu.h/cpp,UIRegistry.h/cpp,OverlayTheme.h/cpp,OverlayLayout.h/cpp,OverlayDraw.h/cpp,OverlayWidgets.h/cpp,OverlayWindowManager.h/cpp,OverlayFonts.h/cpp,OverlayIcons.h/cpp,OverlayThemes.h/cpp.
Extra notes live in docs/wiki/, especially logging/diagnostics and third-party dependency notes.
MIT. See LICENSE.