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:
- Detect: Can this plugin handle this window?
- 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:
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.