A three-part application to monitor active windows and inspect their controls using Microsoft UI Automation API.
native/- Native C++ DLL using Microsoft UI Automation APInapi-plugin/- Node.js Addon (NAPI) wrapping the native DLLelectron/- Electron application with React frontend
You must build in this exact order:
- Open
native/WindowMonitor.slnin Visual Studio 2022 - Select Release configuration and x64 platform
- Build the solution (Ctrl+Shift+B)
- Verify
native/x64/Release/WindowMonitor.dllandWindowMonitor.libexist
cd napi-plugin
pnpm install
pnpm run buildVerify napi-plugin/build/Release/winwatch.node exists.
If binding.cpp shows red squiggles like “napi.h file not found”, that’s usually clangd missing Node/N-API include paths.
We auto-generate napi-plugin/.clangd using:
napi-plugin/scripts/update-clangd.mjs
Commands:
# Regenerate .clangd (auto-detects node-gyp header cache path)
pnpm -C napi-plugin update:clangdNotes:
- This also runs automatically on
pnpm -C napi-plugin installviapostinstall. - If you change Node versions, re-run
pnpm -C napi-plugin update:clangd, then reload the editor window (or restart clangd).
cd electron
pnpm installCopy the DLL to electron folder:
copy ..\native\x64\Release\WindowMonitor.dll .Start the app:
pnpm run dev- Cause: Native DLL not built yet
- Fix: Build the native project in Visual Studio first (Step 1)
- Cause:
WindowMonitor.dllis missing - Fix: Copy
native/x64/Release/WindowMonitor.dllto theelectron/folder
- Cause: NAPI plugin not built
- Fix: Run
pnpm run buildinnapi-plugin/(Step 2)
From the root directory:
# Build NAPI plugin
pnpm run build:napi
# Copy DLL to electron
pnpm run copy:dll
# Run electron app
pnpm run dev- Open
native/WindowMonitor.sln - Set breakpoints
- Debug > Attach to Process > select
electron.exe
cd electron
pnpm run dev:debugThen attach VS Code debugger to Node.js process.
Press Ctrl+Shift+I in the app window to open DevTools.
This repo packages the Windows app using electron-builder with an NSIS installer.
Build the installer from the repo root:
pnpm run build:exe:winOutput is written to electron/dist/.
If you need uiAccess=true (assistive technology / UI Automation scenarios), Windows requires:
- The app EXE has an embedded manifest with
uiAccess="true". - The EXE is code-signed (Authenticode).
- The app is installed in a secure location such as Program Files.
This repo configures NSIS to install per-machine (Program Files) and runs a post-pack step that embeds the UIAccess manifest.
The afterPack hook will sign the final EXE if you provide these environment variables:
WINWATCH_PFX- path to a.pfxcode-signing certificateWINWATCH_PFX_PASSWORD- password for the.pfxWINWATCH_TIMESTAMP_URL- optional RFC3161 timestamp server URL
You also need Windows SDK tools available on PATH:
mt.exe(Manifest Tool)signtool.exe(SignTool) when signing is enabled
Note: If you embed uiAccess="true" but the EXE is not signed with a certificate trusted by the machine, Windows may refuse to start it with the message:
"A referral was returned from the server."
To avoid that, this repo only embeds the uiAccess="true" manifest when code signing is configured (WINWATCH_PFX + WINWATCH_PFX_PASSWORD).
To verify a built EXE is properly signed:
signtool verify /pa /v "path\to\WinWatch.exe"If you don’t have a commercial CA code-signing certificate yet, you can create a self-signed certificate for development/testing on your own machine(s).
Important:
- This is not suitable for public distribution. Other machines won’t trust your EXE unless you install your certificate into their trust stores.
- For
uiAccess=true, Windows requires the EXE to be trusted. With a self-signed cert, that means you must add it to Trusted Root Certification Authorities and Trusted Publishers on the machine.
Quick start (recommended): use the helper script
Run PowerShell as Administrator in the repo root:
./scripts/setup-dev-codesign.ps1 -OutputDir (Resolve-Path .)It will:
- Create (or reuse) a LocalMachine code-signing cert
- Export
winwatch-dev-codesign.pfx+winwatch-dev-codesign.cerinto-OutputDir - Trust the cert by importing it into LocalMachine
RootandTrustedPublisher - Print the exact env vars to set for
pnpm run build:exe:win
Open Windows Terminal / PowerShell as Administrator and run:
$subject = "CN=WinWatch Dev Code Signing"
$cert = New-SelfSignedCertificate \
-Subject $subject \
-Type CodeSigningCert \
-KeyAlgorithm RSA \
-KeyLength 2048 \
-HashAlgorithm SHA256 \
-KeyExportPolicy Exportable \
-CertStoreLocation "Cert:\LocalMachine\My" \
-NotAfter (Get-Date).AddYears(3)
$cert.ThumbprintThis creates the cert in the Local Machine “Personal” store.
$pfxPath = Join-Path $PWD "winwatch-dev-codesign.pfx"
$pfxPassword = Read-Host -AsSecureString "PFX password"
Export-PfxCertificate -Cert ("Cert:\LocalMachine\My\" + $cert.Thumbprint) -FilePath $pfxPath -Password $pfxPassword
$pfxPathExport the public certificate (.cer) and import it into the two trust stores:
$cerPath = Join-Path $PWD "winwatch-dev-codesign.cer"
Export-Certificate -Cert ("Cert:\LocalMachine\My\" + $cert.Thumbprint) -FilePath $cerPath | Out-Null
# Trust chain
Import-Certificate -FilePath $cerPath -CertStoreLocation "Cert:\LocalMachine\Root" | Out-Null
# Trust publisher (important for Authenticode trust decisions)
Import-Certificate -FilePath $cerPath -CertStoreLocation "Cert:\LocalMachine\TrustedPublisher" | Out-Null
$cerPathIf you prefer GUI:
- Run
certlm.msc - Import the
.cerinto:- Local Computer → Trusted Root Certification Authorities
- Local Computer → Trusted Publishers
From cmd.exe (recommended if PowerShell blocks pnpm scripts), set env vars and build:
set WINWATCH_PFX=C:\path\to\winwatch-dev-codesign.pfx
set WINWATCH_PFX_PASSWORD=yourPfxPassword
REM Optional (recommended): your timestamp server URL
REM set WINWATCH_TIMESTAMP_URL=https://timestamp.digicert.com
pnpm run build:exe:winNotes:
- Timestamping is optional for dev. For production, always timestamp.
- The build hook will also auto-locate
mt.exe/signtool.exein Windows Kits; if that fails you can set:WINWATCH_MT_EXEWINWATCH_SIGNTOOL_EXE
signtool verify /pa /v "C:\Program Files\WinWatch\WinWatch.exe"If you see signature verification failures, the cert may not be trusted (repeat step 3) or you may be running the EXE built without signing.
Troubleshooting:
- If you installed Windows SDK but
mt.exe/signtool.exearen’t onPATH, they’re usually under:C:\Program Files (x86)\Windows Kits\10\bin\<version>\x64\mt.exeC:\Program Files (x86)\Windows Kits\10\bin\<version>\x64\signtool.exe
- You can also explicitly point the build hook at the tools:
WINWATCH_MT_EXE(full path tomt.exe)WINWATCH_SIGNTOOL_EXE(full path tosigntool.exe)