chore(startup): name the WebView2 runtime and mark every milestone
His startup.log stops after 'data dir ok', which rules out the two faults already covered and leaves the window creation itself — where a missing WebView2 runtime lands, sometimes as a silent exit rather than an error anyone can print. So the runtime's version is read from where it registers itself (both hives, and the 32-bit view where a per-machine install usually lands) and written BEFORE the window is attempted: 'WebView2: not found' answers the whole question in one line. Breadcrumbs now also mark entering wails.Run, reaching OnStartup, and the window painting — which places any launch that produces nothing between two known points.
This commit is contained in:
@@ -994,6 +994,10 @@ func NewApp() *App { return &App{} }
|
||||
|
||||
func (a *App) startup(ctx context.Context) {
|
||||
a.ctx = ctx
|
||||
// One line in the startup log too, not only in OpsLog's own: the two
|
||||
// together say whether a launch that produced no window got as far as our
|
||||
// code at all, which is the fork every "it does not start" report turns on.
|
||||
bootLog("OnStartup reached")
|
||||
|
||||
dataDir, err := userDataDir()
|
||||
if err != nil {
|
||||
@@ -1554,6 +1558,7 @@ func (a *App) startup(ctx context.Context) {
|
||||
// it — it appears already sized and positioned, never jumping into place after
|
||||
// launch. Show is unconditional: whatever happens above, the window must appear.
|
||||
func (a *App) domReady(ctx context.Context) {
|
||||
bootLog("OnDomReady reached — the window has painted")
|
||||
a.restoreWindowPosition()
|
||||
wruntime.WindowShow(ctx)
|
||||
// The one number that matches what the operator actually experiences: click
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@
|
||||
"The satellite dropdown now follows the list as it is edited: the field read it once when the panel first appeared, so a list saved afterwards only showed up after a restart.",
|
||||
"Preferences no longer redraw with the main window. Being a child of the main view, the whole panel was rebuilt on every cluster spot and every CAT update — several times a second on a busy evening — which looked like a page refreshing constantly and made buttons miss their clicks, the element under the pointer being replaced between the press and the release.",
|
||||
"Dropdown lists open over whatever is beneath them instead of being cut off by it. The satellite list showed one entry of eight, clipped by the panel it sat in.",
|
||||
"A launch that fails before the window exists now says why. OpsLog keeps its log in the data folder beside the program, so anything that went wrong BEFORE that folder existed left nothing to read anywhere — the process appeared and vanished in silence. Startup milestones are written to %LOCALAPPDATA%OpsLogstartup.log, and the three silent exits (already running, the data folder cannot be written — Program Files refuses it — and the window itself failing to open, usually a missing WebView2) now show a message saying which one it was."
|
||||
"A launch that fails before the window exists now says why. OpsLog keeps its log in the data folder beside the program, so anything that went wrong BEFORE that folder existed left nothing to read anywhere — the process appeared and vanished in silence. Startup milestones are written to %LOCALAPPDATA%OpsLogstartup.log, and the three silent exits (already running, the data folder cannot be written — Program Files refuses it — and the window itself failing to open, usually a missing WebView2) now show a message saying which one it was. The log also names the installed WebView2 runtime — the one dependency OpsLog cannot carry inside itself, and whose absence is otherwise invisible — and marks each milestone up to the window painting, so a launch that produces nothing can be placed exactly."
|
||||
],
|
||||
"fr": [
|
||||
"Console Elecraft : les mesures d'émission sont lues dès que la RADIO se déclare en émission, et plus seulement quand OpsLog l'a mise en émission. Passer en émission par le PTT de façade, une pédale ou le bouton du micro laissait le panneau croire à une réception — et comme les barres de puissance et de ROS ne sont lues qu'en émission, elles ne l'étaient jamais pour qui manipule à la main.",
|
||||
@@ -34,7 +34,7 @@
|
||||
"La liste déroulante des satellites suit maintenant la liste au fil des modifications : le champ la lisait une seule fois à l'apparition du panneau, si bien qu'une liste enregistrée ensuite n'apparaissait qu'après un redémarrage.",
|
||||
"Les préférences ne se redessinent plus au rythme de la fenêtre principale. Étant un enfant de la vue principale, tout le panneau était reconstruit à chaque spot du cluster et à chaque mise à jour CAT — plusieurs fois par seconde un soir chargé — ce qui donnait l'impression d'une page qui se rafraîchit sans arrêt et faisait rater les clics, l'élément sous le pointeur étant remplacé entre l'appui et le relâchement.",
|
||||
"Les listes déroulantes s'ouvrent par-dessus ce qui les entoure au lieu d'être coupées par lui. Celle des satellites n'affichait qu'une entrée sur huit, tronquée par le panneau qui la contenait.",
|
||||
"Un lancement qui échoue avant l'apparition de la fenêtre dit maintenant pourquoi. OpsLog tient son journal dans le dossier data, à côté du programme : tout ce qui échouait AVANT la création de ce dossier ne laissait donc aucune trace nulle part — le processus apparaissait et disparaissait en silence. Les étapes du démarrage sont écrites dans %LOCALAPPDATA%OpsLogstartup.log, et les trois sorties silencieuses (déjà lancé, dossier data impossible à écrire — Program Files le refuse — et fenêtre qui ne s'ouvre pas, généralement un WebView2 manquant) affichent désormais un message disant laquelle c'était."
|
||||
"Un lancement qui échoue avant l'apparition de la fenêtre dit maintenant pourquoi. OpsLog tient son journal dans le dossier data, à côté du programme : tout ce qui échouait AVANT la création de ce dossier ne laissait donc aucune trace nulle part — le processus apparaissait et disparaissait en silence. Les étapes du démarrage sont écrites dans %LOCALAPPDATA%OpsLogstartup.log, et les trois sorties silencieuses (déjà lancé, dossier data impossible à écrire — Program Files le refuse — et fenêtre qui ne s'ouvre pas, généralement un WebView2 manquant) affichent désormais un message disant laquelle c'était. Le journal indique aussi la version du runtime WebView2 installé — la seule dépendance qu'OpsLog ne peut pas embarquer, et dont l'absence est autrement invisible — et marque chaque étape jusqu'à l'affichage de la fenêtre, si bien qu'un lancement sans résultat peut être situé précisément."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -114,6 +114,16 @@ func main() {
|
||||
cleanupOldUpdateBinary()
|
||||
}
|
||||
|
||||
// The WebView2 runtime, named before the window is attempted. Its absence is
|
||||
// the classic silent failure — the process starts, the browser environment
|
||||
// cannot be created, and on some machines that ends the launch without an
|
||||
// error anyone can see.
|
||||
if v := webView2Version(); v != "" {
|
||||
bootLog("WebView2 runtime: %s", v)
|
||||
} else {
|
||||
bootLog("WebView2 runtime: NOT FOUND — install Microsoft Edge WebView2 Runtime")
|
||||
}
|
||||
|
||||
// Create an instance of the app structure
|
||||
app := NewApp()
|
||||
app.startupProfile = profileArg(os.Args[1:])
|
||||
@@ -135,6 +145,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Create application with options
|
||||
bootLog("entering wails.Run (window %dx%d, state %v)", width, height, startState)
|
||||
err := wails.Run(&options.App{
|
||||
Title: "OpsLog",
|
||||
Width: width,
|
||||
@@ -168,6 +179,7 @@ func main() {
|
||||
},
|
||||
})
|
||||
|
||||
bootLog("wails.Run returned")
|
||||
if err != nil {
|
||||
// The last thing that can fail before a window exists, and the most
|
||||
// opaque of them: a missing WebView2 runtime lands here. println goes
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
// webView2Version is a Windows question; elsewhere the browser engine comes
|
||||
// with the platform.
|
||||
func webView2Version() string { return "n/a" }
|
||||
@@ -0,0 +1,49 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
// Is the WebView2 runtime actually installed?
|
||||
//
|
||||
// It is the one dependency OpsLog cannot ship inside its own executable, and
|
||||
// its absence is invisible: the process starts, Wails fails to create the
|
||||
// browser environment, and on some machines that failure arrives as a silent
|
||||
// exit rather than as an error we can print. So the version is read straight
|
||||
// from where the runtime registers itself, and written to the startup log
|
||||
// BEFORE the window is attempted — a log that says "WebView2: not found"
|
||||
// answers the whole question in one line.
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// webview2Client is the runtime's own update-client GUID, the key it registers
|
||||
// its version under. Documented by Microsoft for exactly this check.
|
||||
const webview2Client = `Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}`
|
||||
|
||||
// webView2Version returns the installed runtime version, or "" if there is none.
|
||||
//
|
||||
// Both hives: a per-machine install writes to HKLM (and to the WOW6432 view of
|
||||
// it on 64-bit Windows, which is where it usually lands), a per-user install to
|
||||
// HKCU. Missing all three is the answer that matters.
|
||||
func webView2Version() string {
|
||||
type place struct {
|
||||
key registry.Key
|
||||
access uint32
|
||||
}
|
||||
for _, p := range []place{
|
||||
{registry.CURRENT_USER, registry.QUERY_VALUE},
|
||||
{registry.LOCAL_MACHINE, registry.QUERY_VALUE},
|
||||
{registry.LOCAL_MACHINE, registry.QUERY_VALUE | registry.WOW64_32KEY},
|
||||
} {
|
||||
k, err := registry.OpenKey(p.key, webview2Client, p.access)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
v, _, err := k.GetStringValue("pv")
|
||||
k.Close()
|
||||
if err == nil && v != "" && v != "0.0.0.0" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user