When I released lvt, WPF wasn’t on the list. But WPF is still a strong choice for Windows apps — lots of production software runs on it.

So I added it. And while I was at it, I built a plugin architecture that makes extending lvt dramatically easier.

What’s New

WPF Support

WPF applications now get the same treatment as Win32, WinUI 3, and System XAML: full visual tree access with stable element IDs, bounds, and properties.

# Inspect a WPF app
lvt --name MyWpfApp

# Works exactly like before
lvt --name MyWpfApp --screenshot annotated.png

The output is the same clean JSON/XML format, ready for agent consumption.

Plugin Architecture

This is the bigger change. Framework detection is now modular.

Each UI framework is handled by a plugin — a DLL that implements a simple interface:

  1. Detect: Can this plugin handle this window?
  2. Extract: Return the visual tree

lvt loads plugins automatically at startup. Drop a DLL in the plugins folder, restart, done.

Why Plugins?

Windows has a rich app ecosystem with UI frameworks from different eras — WPF, WinForms, UWP, WinUI, and cross-platform options like Flutter, SwiftUI, and Electron. Rather than hardcode every possibility into lvt, the plugin architecture lets anyone add support for their framework of choice.

Build your own detector without touching the lvt codebase. Ship it separately, update on your own schedule. The public lvt repo stays clean.

Mixed-Framework Apps

Real Windows apps are messy. WinUI 3 hosted inside WPF via XAML Islands. Win32 windows with XAML content areas. COM controls inside managed apps.

lvt handles this by running all applicable plugins against each window. The trees get merged into a unified hierarchy:

Window (Win32)
Frame (WPF)
Button "Save"
XamlHost
Grid (WinUI 3)
TextBox "Search"

One tree. Multiple frameworks. No special handling required.

Current Coverage

Framework Status
Win32
WinUI 3
System XAML
ComCtl
WPF ✅ New!
WinForms 🔜
MAUI 🔜
WebView2 🔜

Building a Plugin

Plugins are DLLs that export a C ABI interface. The core functions:

// Return plugin metadata (name, description, API version)
LvtPluginInfo* lvt_plugin_info(void);

// Detect if your framework is present in the target process
int lvt_detect_framework(DWORD pid, HWND hwnd, LvtFrameworkDetection* out);

// Extract the visual tree as JSON
int lvt_enrich_tree(HWND hwnd, DWORD pid, const char* filter, char** json_out);

Drop the DLL in %USERPROFILE%/.lvt/plugins/ and lvt picks it up automatically at startup.

Full documentation and sample plugins are in the repo.

Try It

Same repo, same MIT license, same Copilot CLI skill:

  • GitHub: asklar/lvt
  • Copilot skill: /plugin install asklar/lvt

If you’re using lvt with a framework that’s not yet supported, consider building a plugin and sharing it. The more frameworks covered, the more useful this becomes for everyone.

What framework should I add next? Let me know on LinkedIn or X.

Updated: