For writing keygen, only limited types of widgets are needed, such as EditBox/Button/ComboBox/CheckBox etc.
Dear ImGui is a good GUI framework for writing keygen, with the concept of "Immediate Mode GUI", which is quite different from stateful GUI framework such as MFC/Qt etc. The generated EXE is less than 200KB with "Win32 + DirectX" binding and static CRT linking and /OPT:REF and /OPT:ICF. If you cut some source code manually, or use VC-LTL(https://github.com/Chuyu-Team/VC-LTL), EXE size can be decreased more.
It also has bindings for MacOS and Linux, which means you can also easily write small-size GUI keygen for MacOS and Linux, though different bindings require recompiling. If you want universal binding, SDL binding may be a choice, but the file size may increase.
github(we can play with its examples. The author of Dear ImGUI is quite active):
https://github.com/ocornut/imgui
some hints:
1. uncomment the following macros to cut gamepad support and directx xinput to decrease file size and remove xinput dll dependency.
Code:
#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
2.disable "imgui.ini" saving/loading. or remove related code.
Code:
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = NULL;
3. there are 3 built-in color styles, just choose one of them or add your own.
Code:
//ImGui::StyleColorsDark();
ImGui::StyleColorsClassic();
//ImGui::StyleColorsLight();
4. load your own fonts.
Code:
ImGuiIO& io = ImGui::GetIO();
font = io.Fonts->AddFontFromFileTTF(u8"c:\\windows\\fonts\\cour.ttc", 16.0f * highDPIscaleFactor,...)
5. DPI scaling.
get DPI scaling factor "highDPIscaleFactor" for current desktop window, then multiply any height/width with this factor.
Code:
ImGui_ImplWin32_EnableDpiAwareness();
float highDPIscaleFactor = ImGui_ImplWin32_GetDpiScaleForHwnd(GetDesktopWindow());
set auto scaling when creating widgets without height/width specified:
Code:
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(highDPIscaleFactor);
multiply the height/width of Win32 main window with highDPIscaleFactor:
Code:
HWND hwnd = ::CreateWindow(wc.lpszClassName, L"window demo title", WS_POPUPWINDOW, 0, 0, WINDOW_WIDTH * highDPIscaleFactor, WINDOW_HEIGHT * highDPIscaleFactor, NULL, NULL, wc.hInstance, NULL);
multiply the font size with highDPIscaleFactor:
Code:
ImGuiIO& io = ImGui::GetIO();
font = io.Fonts->AddFontFromFileTTF(u8"c:\\windows\\fonts\\cour.ttc", 16.0f * highDPIscaleFactor,...)
multiply the child window width with highDPIscaleFactor:
Code:
ImGui::BeginChild("Child", ImVec2(0, 90 * highDPIscaleFactor), true, window_flags);
I will not cover how to respond to DPI-changed message of Windows here, just add it by yourself if needed.
6. specify widget width with font size.
note: font size returned by ImGui::GetFontSize() is already DPI-scaled.
25.0 is the number of chars. If you use CJK font, the font width is double of English fonts, the width of 1 CJK char is that of 2 English chars.
Code:
ImGui::PushItemWidth((float)(int)(ImGui::GetFontSize() * 25.0f));
...
ImGui::PopItemWidth();
7. hide Win32 main window title bar, and drag window with window widget title bar(this part is for Win32 only)
A window widget is a kind of ImGui widgets whose type is "window".
hide win32 main window title:
just pass WS_POPUPWINDOW instead of WS_OVERLAPPEDWINDOW to CreateWindow.
Code:
HWND hwnd = ::CreateWindow(wc.lpszClassName, L"demo", WS_POPUPWINDOW, 0, 0, WINDOW_WIDTH * highDPIscaleFactor, WINDOW_HEIGHT * highDPIscaleFactor, NULL, NULL, wc.hInstance, NULL);
create a widget whose type is "window". A "close" button will apear in the title bar of this widget, but no minimize/maximize button supported yet. Fill all of its parent window(i.e. client area of Win32 main window) with this widget.
save the title bar height in a global variable for later use.
Code:
static int titleBarHeight = 0;
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
bool windowStatus = true;
ImGui::Begin(u8"demo window widget title", &windowStatus, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings);
if (!titleBarHeight)
titleBarHeight = ImGui::GetFrameHeight();
if user clicks the "close" button of this window widget, call PostQuitMessage:
Code:
if (!windowStatus)
::PostQuitMessage(0);
in WndProc() of Win32 main window, check whether user is dragging the title bar of this window widget and move the title-less Win32 window accordingly.
Code:
static bool dragWindow = false;
// Win32 message handler
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
return true;
static POINT startPos;
switch (msg)
{
case WM_LBUTTONDOWN:
startPos.x = (int)(short)LOWORD(lParam);
startPos.y = (int)(short)HIWORD(lParam);
if (titleBarHeight > 0 && startPos.y <= titleBarHeight)
{
dragWindow = true;
SetCapture(hWnd);
}
break;
case WM_LBUTTONUP:
if (dragWindow)
{
dragWindow = false;
ReleaseCapture();
}
break;
case WM_MOUSEMOVE:
if (dragWindow && (wParam & MK_LBUTTON))
{
RECT mainWindowRect;
POINT pos;
int windowWidth, windowHeight;
pos.x = (int)(short)LOWORD(lParam);
pos.y = (int)(short)HIWORD(lParam);
GetWindowRect(hWnd, &mainWindowRect);
windowHeight = mainWindowRect.bottom - mainWindowRect.top;
windowWidth = mainWindowRect.right - mainWindowRect.left;
ClientToScreen(hWnd, &pos);
MoveWindow(hWnd, pos.x - startPos.x, pos.y - startPos.y, windowWidth, windowHeight, TRUE);
}
break;
8. add keyboard support for widgets, such Ctrl + C to copy text.
Code:
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
A keygen template source code repo deserves many words, but currently no time to do it yet. If anyone would like to help, it will be nice.