I recently built Driver Booster Pro, an open-source Windows driver scanner and update manager. What started as a simple CLI tool grew into a full desktop app with a native Windows 11 look. Here's how I built it using Go and Microsoft WebView2, and the Win32 API tricks that made it feel truly native.

Download Driver Booster Pro

Windows 10/11 • Portable EXE • No installer required

Download EXE View Source
Driver Booster Pro - Main Dashboard

Why Go + WebView2?

I wanted a few things from this project:

  • Single binary — no installer, no runtime dependencies to bundle
  • Web-tech UI — HTML/CSS/JS because I know it and it's flexible
  • Native feel — no Electron bloat, no obvious web view chrome
  • Full Win32 access — for driver enumeration, Windows Update, system info

Go + WebView2 hits the sweet spot. go-webview2 by jchv wraps the Microsoft Edge WebView2 runtime, which is pre-installed on Windows 10+. The final binary is ~10 MB — compared to 150+ MB for an Electron app.

The Architecture

The app is structured as a local HTTP server + WebView2 client:

┌─────────────────────────────────────┐
│  WebView2 Window (HTML/CSS/JS UI)  │
│           ▲                         │
│           │ fetch('/api/drivers')  │
│           ▼                         │
│  Local HTTP Server (Go)            │
│           │                         │
│           ▼                         │
│  PowerShell / Win32 API calls      │
└─────────────────────────────────────┘

On startup, Go spins up an HTTP server on 127.0.0.1:0 (random free port), serves the embedded UI assets, and hands the URL to WebView2. The frontend calls /api/* endpoints that execute Windows operations on the backend.

Embedding the Entire UI in the EXE

Go 1.16+ has embed built-in. One line pulls every UI file into the binary:

//go:embed ui/*
var uiFS embed.FS

func main() {
    uiContent, _ := fs.Sub(uiFS, "ui")
    mux.Handle("/", http.FileServer(http.FS(uiContent)))
    // ...
}

HTML, CSS, JS, and 27 PNG icons — all compiled into the EXE. Ship one file, no asset folders.

The "Hidden CMD Window" Problem

This is where most Go Windows apps fall apart. Two issues:

1. Main app opens a console window

By default, go build produces a console application. When you double-click the EXE, Windows shows a console window. The fix is the linker flag:

go build -ldflags "-H windowsgui" -o driver-booster.exe .

-H windowsgui tells the PE header to use the Windows GUI subsystem — no console, no flash.

2. Subprocess calls (PowerShell) flash a window

Every exec.Command("powershell", ...) call pops up a CMD window briefly. The fix is setting SysProcAttr:

func HiddenCommand(name string, args ...string) *exec.Cmd {
    cmd := exec.Command(name, args...)
    cmd.SysProcAttr = &syscall.SysProcAttr{
        CreationFlags: 0x08000000, // CREATE_NO_WINDOW
    }
    return cmd
}

The CREATE_NO_WINDOW flag prevents the console window from ever being created for the child process.

Making It Look Native: Frameless Window

WebView2's default window has a native Windows title bar. That's fine, but I wanted a custom title bar with a status indicator and brand colors. The trick: remove WS_CAPTION from the window style via Win32 API.

var (
    user32            = syscall.NewLazyDLL("user32.dll")
    procGetWindowLong = user32.NewProc("GetWindowLongW")
    procSetWindowLong = user32.NewProc("SetWindowLongW")
    procSetWindowPos  = user32.NewProc("SetWindowPos")
)

func removeWindowFrame(hwnd uintptr) {
    gwlStyle := uintptr(0xFFFFFFF0) // GWL_STYLE = -16 as unsigned
    style, _, _ := procGetWindowLong.Call(hwnd, gwlStyle)
    newStyle := (style &^ 0x00C00000) | 0x00040000 // remove WS_CAPTION, keep WS_THICKFRAME
    procSetWindowLong.Call(hwnd, gwlStyle, newStyle)
    procSetWindowPos.Call(hwnd, 0, 0, 0, 0, 0, 0x0020|0x0002|0x0001|0x0004)
}

After creating the WebView2 window, I grab its HWND via w.Window() and call removeWindowFrame(). The native title bar vanishes but the window stays resizable because WS_THICKFRAME is preserved.

Custom window controls

With the title bar gone, I need my own min/max/close buttons. I bind Go functions to JavaScript:

w.Bind("windowMinimize", func() {
    procPostMessage.Call(hwnd, 0x0112, 0xF020, 0) // WM_SYSCOMMAND + SC_MINIMIZE
})
w.Bind("windowClose", func() {
    procPostMessage.Call(hwnd, 0x0112, 0xF060, 0) // SC_CLOSE
})

In HTML:

Making the title bar draggable

You might think -webkit-app-region: drag CSS works. It does not — that's an Electron-specific property. In WebView2, you need the Win32 message trick:

w.Bind("windowDrag", func() {
    procReleaseCapture.Call()
    procSendMessage.Call(hwnd, 0x00A1, 2, 0) // WM_NCLBUTTONDOWN, HTCAPTION
})

Then on the title bar:

...

When you mousedown on the title bar, we tell Windows "this click is actually on a caption area", and Windows handles the drag natively. The window moves with the cursor exactly like a normal app — including snapping to screen edges.

Collecting System Info via Win32 API

For RAM, disk, and OS version, I used direct syscalls instead of PowerShell for speed and accuracy:

var (
    kernel32           = syscall.NewLazyDLL("kernel32.dll")
    procGlobalMemoryEx = kernel32.NewProc("GlobalMemoryStatusEx")
    ntdll              = syscall.NewLazyDLL("ntdll.dll")
    procRtlGetVersion  = ntdll.NewProc("RtlGetVersion")
)

var mem memoryStatusEx
mem.Length = uint32(unsafe.Sizeof(mem))
procGlobalMemoryEx.Call(uintptr(unsafe.Pointer(&mem)))

Why RtlGetVersion instead of GetVersion? Because Windows lies. GetVersion returns whatever the app manifest claims — it's subject to compatibility shims. RtlGetVersion from ntdll.dll always returns the true version, which matters for a system utility.

System Information Tab

Driver Enumeration via WMI

For drivers, I punted to PowerShell because calling SetupAPI from Go is painful. This one-liner gives me everything I need:

Get-CimInstance Win32_PnPSignedDriver |
  Where-Object { $_.DeviceName -ne $null } |
  Select-Object DeviceName, DeviceClass, Manufacturer,
    DriverVersion, DriverDate, InfName, IsSigned, Status |
  ConvertTo-Json -Compress

Go executes this via HiddenCommand(), parses the JSON, and renders it to the UI. Each driver gets a contextual icon based on its DeviceClass — monitor for displays, wifi for network adapters, cpu for processors, etc.

Driver List with Action Buttons

Windows Update via COM

For checking updates, I use the Windows Update Agent COM API (also via PowerShell):

$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$SearchResult = $Searcher.Search("IsInstalled=0")

This returns pending updates with KB article IDs, categories, download sizes, and severity — everything the UI shows.

Windows Update Checker

WinUI3 Dark Theme in CSS

To match Windows 11's design language, I used the Mica palette as CSS variables:

:root {
    --bg: #202020;           /* Mica dark base */
    --surface: #2d2d2d;
    --card: #323232;
    --border: rgba(255,255,255,0.0578);
    --accent: #60cdff;       /* Win11 accent */
    --accent-bg: #0078d4;
    --text: #ffffffde;
}

body { font-family: 'Segoe UI Variable', 'Segoe UI'; }

These values come straight from the WinUI3 design tokens. The result looks like a first-party Microsoft app — Settings, PC Manager, that kind of vibe.

Embedding the App Icon

For the EXE icon (shown in taskbar, Explorer, ALT+TAB), I used go-winres:

go install github.com/tc-hib/go-winres@latest
go-winres init
# place icon.png in winres/ and edit winres/winres.json
go-winres make
go build -ldflags "-H windowsgui" -o driver-booster.exe .

go-winres make generates .syso files that the Go linker automatically embeds. Right-click the EXE and you'll see proper Version, Company Name, and Description metadata.

Lessons Learned

  • WebView2 is excellent for this kind of app — fast, stable, and preinstalled on modern Windows
  • Don't fight Win32 — for a truly native look, you need direct API calls
  • PowerShell is a fine escape hatch for WMI/COM complexity — just hide the console window
  • Go embed changed the game — no more asset management pain
  • 10 MB beats 150 MB — Electron tax is real, and users notice

Screenshots

Initial Scan Page Loading Overlay

Source & Download

Feel free to fork, extend, or steal the Win32 tricks for your own Go desktop apps. The frameless window pattern alone took me a few hours to get right — hopefully this saves you the debugging time.


Made by IMTAQIN