Windows launch path
On Windows, vericue run starts an unmodified Qt application with the veriCue Runtime inside it, the same way it does on Linux and behind the same command:
vericue run --port 4242 .\your-qt-app.exe
# VERICUE_PORT=4242The mechanism underneath is different from Linux, and that difference has real consequences for antivirus and endpoint security. Read this page before you rely on the Windows launch path in CI or on a managed fleet.
Not serverless
As on every platform, veriCue Runtime code runs inside your application process. vericue run changes how the Runtime gets there, not where it runs. Full QObject / QWidget / QQuickItem introspection requires code in the process, and this path provides exactly that.
What it does
vericue run selects the Windows backend, which delegates to vericue-inject.exe from the Windows package's bin\. That launcher:
- preflights the target - it parses the target's PE import directory and refuses, before launching anything, a target that is not x64, does not import a dynamic Qt (
Qt5Core.dll/Qt6Core.dll), links Qt statically, or is a.bat/.cmdwrapper rather than the application binary. Each refusal names the cause, a corrective action, and the embedding fallback; - launches the target suspended with
CreateProcess(CREATE_SUSPENDED)- the process is created and mapped, but not one instruction of its own code has run; - loads
vericue-inject.dllinto it withCreateRemoteThread+LoadLibraryW, before the application starts. That DLL is the same probe the Linux package preloads; itsQ_COREAPP_STARTUP_FUNCTIONfires the moment the application constructs itsQApplication, and starts the sameVeriCueServeran embedder would; - resumes the target and supervises it to its own exit code.
The probe reads its configuration from the environment exactly as the Linux probe does, so authentication, licensing and concurrent-session behaviour are identical to an embedded Runtime and to the Linux injector. A licensing configuration you asked for and that cannot be applied refuses the run rather than silently degrading to a trial.
How the Qt check is made
The launcher decides "does this application link a dynamic Qt" by reading the target's import table - the list the Windows loader itself acts on - and not by searching the file for the text Qt6Core.dll. The difference matters: a launcher, updater or plugin host may carry the name of a Qt DLL in a resource, a log message or a table of libraries it loads later with LoadLibrary, and naming a DLL is not linking it. Such a binary is refused, because injecting into it would put the probe in a process with no Qt to attach to.
The same parsed import set decides the reported toolkit, so --check reports widgets or quick only when the corresponding module is genuinely imported.
A delay-loaded Qt is recognised, but not supported. If the target's only Qt6Core.dll dependency sits in the delay-import directory (linked with /DELAYLOAD), the launch is refused. Not because the linkage is fake - it is real, and the probe hooks the construction of QCoreApplication via Q_COREAPP_STARTUP_FUNCTION rather than module load order, so the Runtime would start. The reason is which Qt the process ends up with: a delay-imported QtCore is not mapped when the probe loads, so the probe's own QtCore resolves first from the child's DLL search path and the target's later delay-load binds to that module instead of the one it intended.
An application that delay-loads Qt usually does so precisely because it computes or adds the Qt directory itself at run time - which is exactly the decision this would silently override. Treating it as supported needs evidence from a real delay-loaded Qt application rather than a reading of its import table, so it stays refused until that evidence exists.
Embed the veriCue server for such an application. If you want to override the check deliberately, --no-preflight skips it along with every other check; the --check report then shows what you are overriding:
target Qt 6.x (delay-imported)A target whose import table cannot be read - truncated, packed or corrupt - is refused rather than injected into on a guess.
Transport: TCP only
Windows exposes TCP only in this release. Local IPC over named pipes is not implemented and is not claimed. The default when you name no transport is an OS-chosen TCP port, announced on the target's stdout as VERICUE_PORT=<n>:
vericue run .\your-qt-app.exe # VERICUE_PORT=<os-chosen>
vericue run --port 4242 .\your-qt-app.exe--endpoint (local IPC) is refused on Windows with a concrete reason. Because the default port is chosen by the OS and is not known until the target runs, --announce on Windows requires an explicit --port N; otherwise read the VERICUE_PORT=<n> line from the target's stdout.
TCP is plaintext and reachable from other hosts
It is unauthenticated unless you pass --token. See Transports.
Security, antivirus and EDR
CreateRemoteThread + LoadLibraryW is a textbook code-injection pattern. It is exactly what antivirus and endpoint-detection-and-response (EDR) products are built to detect, and they may block, quarantine or silently kill it, even though your use is legitimate and the DLL is your own veriCue package.
We do not, and cannot, promise this technique survives any given endpoint security product. Specifically:
- Windows Defender on a stock machine usually allows a user launching a local process and loading a local DLL into it. But Attack Surface Reduction (ASR) rules - notably "Block process creations originating from PSExec and WMI commands" and the process-injection heuristics - can block it, and a managed tenant may have ASR enabled by policy.
- Third-party EDR/AV (CrowdStrike, SentinelOne, Defender for Endpoint, Carbon Black and similar) commonly flag remote-thread injection as an indicator of compromise. On a managed fleet this can raise an alert or kill the injected process. We claim no universal compatibility with these products.
- Protected or specially hardened targets (a process with a protected-light signer, or one running under a restrictive mitigation policy) may reject the injection outright. The launcher reports the failure and points at embedding.
When injection is blocked, the launcher does not leave the application half running: a failure before the target is resumed terminates the suspended process, so there is no orphan and no partially instrumented app.
Code signing
The veriCue Windows binaries are not currently Authenticode-signed. You should know that before you run them, because it is exactly the sort of thing you would otherwise discover from a SmartScreen dialog: Windows will report an unknown publisher for vericue-inject.exe, and the DLLs it loads carry no signature either.
Verify what you downloaded with the published checksum instead. Every archive on dl.vericue.dev ships a .sha256 beside it:
(Get-FileHash .\vericue-0.4.0-qt6.7-windows-x64.zip -Algorithm SHA256).Hash
# compare against vericue-0.4.0-qt6.7-windows-x64.zip.sha256Signing is planned, and the release pipeline already has the hook for it, so the change will be visible as signed packages rather than as a documentation edit.
Be clear about what signing will and will not buy, because the common advice on this is out of date. An Extended Validation certificate no longer grants SmartScreen reputation on its own - Microsoft's own guidance now states that paying a premium for EV solely to avoid SmartScreen warnings is not justified. Reputation accrues to the file hash and the publisher identity through download volume, so a signed first release of a niche tool can still be flagged as unrecognised.
What signing does buy is a verified publisher name instead of "unknown publisher", reputation that carries across releases signed with the same identity, and a basis for disputing a false positive with an AV vendor. On Windows 11 it also matters for Smart App Control, which blocks unsigned binaries outright rather than merely warning.
It does not exempt the runtime injection itself from EDR behavioural detection: signing establishes who produced the binary, not that a remote-thread injection is benign. Treat signing as necessary hygiene, not as a guarantee, and expect this section to stay relevant after the binaries are signed.
What to do in a hardened environment
If your endpoint security blocks the launch, embed the veriCue Runtime in the application and connect over TCP. Embedding needs no injection, works on every platform, can be compiled out of release builds, and is the recommended setup for CI on managed machines:
#include <vericue/server.h>
vericue::VeriCueServer server(&app);
server.setAuthToken("s3cret");
server.start(4242); // TCPSee Embedding the server. This is not a downgrade - it is the configuration that always works.
Check before you run
vericue run --check .\your-qt-app.exevericue-inject: preflight OK
target C:\app\your-qt-app.exe (PE x64)
target Qt 6.x (imported)
toolkits widgets
probe C:\vericue\bin\vericue-inject.dll
probe build veriCue 0.4.0, Qt 6.7.2
runtime C:\vericue\bin
transport TCP port auto (0, announced as VERICUE_PORT)
docs https://vericue.dev/docs/guides/injector--check runs the preflight and exits without launching anything. It is the first thing to attach to a support request.
Packaging layout
The launcher, the probe and the Runtime must stay together. In the Windows package they all live in bin\:
bin\
vericue-inject.exe the launcher
vericue-inject.dll the probe loaded into the target
vericue-server.dll the Runtime
vericue-widgets.dll Widgets toolkit plugin (loaded on demand)
vericue-quick.dll Qt Quick toolkit plugin (loaded on demand)Windows does not search a loaded DLL's own directory for its dependencies, so the launcher prepends its own bin\ and the target's directory to the child's PATH. That resolves vericue-server.dll from the package and the target's own Qt from beside the application (the windeployqt layout). Keep bin\ intact: moving vericue-inject.dll away from vericue-server.dll breaks the run with a "probe failed to load" diagnostic.
Point VERICUE_HOME at the package root, or put bin\ on %PATH%:
$env:VERICUE_HOME = "C:\vericue"
vericue run .\your-qt-app.exeWhat is out of scope
- Attaching to an already-running process is not supported.
vericue runstarts the target itself; it does not inject into a process you started earlier. - Windows local IPC (named pipes) is not implemented. Use TCP.
- Non-x64 targets (x86, ARM64) are refused: the probe is x64 and runs inside the target's own process, so the two must match.

