Let a second copy yield to the instance already running

listen() was the whole of the single-instance check and it cannot be one:
a Windows named pipe takes a second server on the same name rather than
refusing it, and everywhere else removeServer() first takes the live socket
away from the instance holding it. Starting Dikte over a running Dikte then
left two whole copies up, two tray icons and all, and the newer one's
sweep() killed the whisper the older one was answering dictations with. On
a machine that sleeps instead of logging out, that is one Start Menu click
away, and it cost a real dictation before it was understood.

A QLockFile in the data directory closes the race on all three systems,
taken before the QApplication is even built, and behind it the probe is the
side-effect-free status verb: the Settings window opens as the sign of life
only when a bare second start deliberately asks for it, not as a byproduct
of a probe racing a forwarded toggle. The two Windows relaunch dances
collapse into one ipc.respawn.

The checkout installer and the packaged setup each kept an autostart the
other could not see, so a machine that tried both started two copies at
every sign-in: each autostart now removes the other's entry, the silent
every-start repair backs off from a Run value whose target still exists,
and each uninstaller deletes the shared dikte.cmd only when the shim
names its own install.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
huseyin-emre-tigci
2026-08-22 23:09:05 +03:00
co-authored by Claude Fable 5
parent 0a70484d84
commit 6f601ab969
7 changed files with 308 additions and 17 deletions
+21 -1
View File
@@ -23,9 +23,20 @@ $autostartLink = Join-Path $startup "Dikte.lnk"
$cmdShim = Join-Path $env:LOCALAPPDATA "Microsoft\WindowsApps\dikte.cmd"
if ($Uninstall) {
foreach ($path in @($shortcut, $autostartLink, $cmdShim)) {
foreach ($path in @($shortcut, $autostartLink)) {
if (Test-Path $path) { Remove-Item $path -Force; Write-Host "removed: $path" }
}
# The packaged install writes the same shim, naming its own dikte-cli.exe.
# Only the one naming this checkout is ours to delete; taking the other
# would break the `dikte` command of an install this script never made.
if (Test-Path $cmdShim) {
if ((Get-Content $cmdShim -Raw).Contains($entry)) {
Remove-Item $cmdShim -Force
Write-Host "removed: $cmdShim"
} else {
Write-Host "left alone: $cmdShim (it names another install, not this checkout)"
}
}
Write-Host "Dikte's shortcuts are gone. The repository and your settings are not."
exit 0
}
@@ -65,6 +76,15 @@ foreach ($path in @($shortcut) + $(if ($Autostart) { @($autostartLink) } else {
Write-Host "shortcut: $path"
}
if ($Autostart) {
# The packaged build keeps its sign-in entry in the registry. Left there
# beside the shortcut written above, both would start a Dikte at sign-in,
# and this install is the one being asked for.
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" `
-Name "Dikte" -ErrorAction SilentlyContinue
Write-Host "autostart: the Startup shortcut replaces any registry Run entry a packaged install left"
}
# --- the dikte command ------------------------------------------------------
# The interpreter by its full path rather than by name: the one checked above is
# the one the command line should run, whatever a later PATH change puts first.