DEV Community

Cover image for How I Built a 20-in-1 Windows Toolbox with C++20 + MFC
Yuxuan Guan
Yuxuan Guan

Posted on

How I Built a 20-in-1 Windows Toolbox with C++20 + MFC

Open source: https://github.com/gyx114/PowerBox | MIT License

Intro

A while ago I set myself a "practice" goal: write a C++ desktop app that I actually use every day — not another dead repo.

That's how PowerBox was born: a Windows toolbox that bundles an AI assistant, process manager, screen OCR, clipboard history, Git toolbox, batch rename, and 20+ utilities. Its most distinctive feature is this: the built-in AI assistant doesn't just answer questions — it can open a terminal, run commands by itself, and paste the results back into the conversation.

This post won't be a feature list. Instead, I want to share the three parts that matter most to developers:

  1. How I modernized an old MFC project (WebView2 migration, modular architecture)
  2. How the AI assistant executes commands through a built-in ConPTY terminal
  3. The "encoding consistency" trap that's easiest to overlook in a multi-language project

1. Tech Stack

Item Choice
Language / Standard C++20
UI Framework MFC (Microsoft Foundation Classes)
AI Integration WinHTTP + 6 AI providers
Markdown / AI Rendering WebView2 (replacing WebBrowser)
Terminal ConPTY (Windows Pseudo Console)
JSON Nlohmann json.hpp
QR Code Nayuki QR Code Generator
Localization External INI files (UTF-16 LE)
Distribution Static-linked MFC/CRT, single exe + lang + res

Why MFC? It's the most mature and stable C++ desktop framework on Windows, and this project is a "small but strong" monolith — no need to drag in Qt's heavyweight dependency tree.

2. Architecture: Turning a 1,000-line Dialog into Clean Modules

The most common way MFC projects die: everything gets dumped into OnInitDialog and a few callbacks, and after a few thousand lines nobody dares to touch it. My approach was two things.

1. Split the main dialog by responsibility into separate source files

MFCApplication1Dlg_Buttons.cpp   // quick-launch buttons
MFCApplication1Dlg_File.cpp      // file / folder management
MFCApplication1Dlg_Process.cpp   // process management
MFCApplication1Dlg_Startup.cpp   // startup items
MFCApplication1Dlg_Terminal.cpp  // terminal
MFCApplication1Dlg_Tray.cpp      // tray
MFCApplication1Dlg_Window.cpp    // window tools
Enter fullscreen mode Exit fullscreen mode

2. Extract reusable capabilities into independent modules

Anything "UI-agnostic" — clipboard history, volume control, auto-clicker, OCR, process enumeration — lives in a separate Manager/Engine class. The main window just composes them. Each module can be tested in isolation, and the code is ready to be split into separate tools later.

ProcessManager / ClipboardManager / VolumeManager / AutoClicker / OcrEngine / LocalizationManager
Enter fullscreen mode Exit fullscreen mode

3. Three Key Implementations

3.1 AI Assistant: Replacing WebBrowser with WebView2

Early versions rendered the AI panel and Markdown preview with WebBrowser (MSHTML) — poor rendering and painful state management. I migrated everything to WebView2.

The key design is two-way communication between HTML and C++. The "Run" button on a command card calls from HTML:

<script>
  function execCmd(id) {
    // send the command id to C++ via WebView2 postMessage
    chrome.webview.postMessage(id);
  }
</script>
Enter fullscreen mode Exit fullscreen mode

On the C++ side, OnWebMessageReceived receives the message and forwards it to the main dialog as a custom message:

void CMFCApplication1Dlg::OnWebMessageReceived(
    const std::wstring& msg)
{
    // parse message → resolve command → trigger execution
    PostMessage(WM_AI_EXECUTE_COMMAND, ...);
}
Enter fullscreen mode Exit fullscreen mode

The benefit: rendering (HTML/CSS) and logic (C++) are fully decoupled. Font sizes, themes, and scroll positioning can be handled via ExecuteScript on the DOM without reloading the page — which is exactly what keeps the AI conversation state intact.

3.2 AI Executing Commands: Talking to a ConPTY Terminal

PowerBox ships a built-in ConPTY terminal with multiple sessions and tab switching. The AI command execution flow is:

AI generates command → confirmation dialog (shows purpose & risk level)
→ dispatched to a new terminal tab → async output read → result pasted back
Enter fullscreen mode Exit fullscreen mode

The core of ConPTY is CreatePseudoConsole + CreateProcess attached to the pseudo console, with a background thread reading the pipe. The critical rule: always use a background thread + stop token, never block the UI thread waiting for output:

// std::jthread auto-joins; stop_token enables cancellation
std::jthread worker([stop = std::stop_source{}] {
    while (!stop.get_token().stop_requested()) {
        // read pipe output → notify UI to update
    }
});
Enter fullscreen mode Exit fullscreen mode

Security gets two layers: the confirmation dialog shows the command's purpose and risk level and requires explicit user approval, and AI-generated commands are never silently executed.

3.3 Localization: The Encoding-Consistency Trap Nobody Warns About

PowerBox supports 5 languages (CN/EN/JA/KO/RU) with language packs in external lang/*.ini. This is the area most likely to blow up, because the encoding requirements are strict:

  • .rc resource files = UTF-16 LE BOM
  • lang/*.ini language packs = UTF-16 LE BOM

If you edit a .rc file with a regular editor, it silently converts to UTF-8 and the RC compiler starts throwing weird errors like RC4093 / RC2255. The safe way is to control the encoding explicitly with PowerShell:

# .rc or .ini edits must read/write as UTF-16 LE
$content = [System.IO.File]::ReadAllText("xxx.rc", [System.Text.Encoding]::Unicode)
$content = $content.Replace("old string", "new string")
[System.IO.File]::WriteAllText("xxx.rc", $content, [System.Text.Encoding]::Unicode)
Enter fullscreen mode Exit fullscreen mode

This deserves emphasis: in a multi-language project, encoding consistency causes more damage than feature bugs — and it surfaces as garbled Chinese, the hardest kind of bug to debug.

4. Distribution: Static Linking, Portable Single Exe

MFC/CRT are fully statically linked, and the release artifact is only 4 items:

PowerBox.exe          // main executable
WebView2Loader.dll    // WebView2 loader
lang/                 // 5 language packs
res/                  // Markdown rendering resources
Enter fullscreen mode Exit fullscreen mode

No runtime installation needed — unzip and run, no registry writes, which fits a "toolbox you can carry anywhere" positioning. The WebView2 Runtime is pre-installed on Win10/11 in most cases, so only the loader DLL needs to ship.

5. Pitfall Checklist (Save Yourself Three Months)

Ranked by how much they cost me:

  1. Encoding consistency (most expensive): .rc / lang/*.ini must be UTF-16 LE — wrong encoding equals garbled Chinese plus RC compile errors, the hardest thing to debug
  2. Blocking the UI thread: OCR, translation, and terminal reads must run on background threads (std::jthread + stop_token); calling .get() on the UI thread freezes the whole app
  3. Resource ID collisions: before adding any control, check resource.h / .rc / the message map — duplicate IDs plant landmines in both compile time and runtime
  4. Non-modal dialog destruction: calling DestroyWindow() directly accesses a freed this; use PostMessage(WM_CLOSE) for deferred destruction
  5. Tool windows minimized with the main window: tool windows must use nullptr as parent so they're independent
  6. Screenshot overlay flicker: recreating a DIB and filling the whole screen on every mouse drag causes severe flicker; pre-create a DIB and do incremental double-buffered updates
  7. Don't hand-roll QR codes: error-correction logic is full of edge cases; just use a proven library like Nayuki's
  8. .gitignore encoding too: a UTF-16-encoded .gitignore makes Git misparse rules (e.g. *.aps becomes *)

6. Open Source & What's Next

PowerBox is currently v4.1.0, MIT licensed, with source and releases on GitHub:

https://github.com/gyx114/PowerBox

The README is available in 5 languages with a full feature table and screenshots. If you're working on C++/MFC projects, or you're curious about the "AI assistant + terminal" interaction pattern, come check out the repo. A star is the biggest encouragement.

Questions, bug reports, or MFC development chat — feel free to reach out via Issue or comments.

Top comments (0)