babalae/better-genshin-impact · error · InvalidOperationException

BvFlow 已经开始执行,不能再添加步骤

Error message

BvFlow 已经开始执行,不能再添加步骤

What it means

Thrown from SetSmartSizing when the already-connected RDP ActiveX control's AdvancedSettings7 property returns null. Unlike the connect-time variant (errorIndex 2), this fires post-connection when toggling display scaling at runtime. It indicates the control's COM state degraded after the initial connection or the control was disposed/recreated between connect and this call.

Source

Thrown at BetterGenshinImpact/Core/BgiVision/BvFlow.cs:277

    }

    internal BvFlow AddActionStep(BvFlowActionSnapshot snapshot)
    {
        return AddStep(snapshot.Description, context => ExecuteActionStep(snapshot, context));
    }

    internal BvFlow AddOnceActionStep(string description, Func<BvFlowExecutionContext, Task> action)
    {
        return AddStep(description, action);
    }

    internal BvFlowAction CreateAction(string description, Func<BvFlowExecutionContext, Task> action)
    {
        lock (_syncRoot)
        {
            if (_hasStarted)
            {
                throw new InvalidOperationException("BvFlow 已经开始执行,不能再添加步骤");
            }
        }

        return new BvFlowAction(this, description, action);
    }

    internal BvLocator CreateTextLocator(string text, Rect rect)
    {
        return _page.Locator(new RecognitionObject
        {
            RecognitionType = RecognitionTypes.Ocr,
            RegionOfInterest = rect,
            Text = text
        });
    }

    internal BvLocator CreateAnyTextLocator(object texts, Rect rect)
    {

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Guard SetSmartSizing with a check that ConnectedState == 1 and the control is not disposing before accessing AdvancedSettings7.
  2. Cache the setting in _smartSizingEnabled (already done) and re-apply it on next ConnectToChildSession rather than throwing post-disconnect.
  3. Wrap the property access in try-catch and log a warning instead of throwing when the control is in a transitional state.

Example fix

// before
internal void SetSmartSizing(bool enabled)
{
    _smartSizingEnabled = enabled;
    if (!IsHandleCreated) return;
    var advancedSettings = GetComProperty(GetRequiredOcx(), "AdvancedSettings7")
        ?? throw new COMException("RDP ActiveX 未返回 AdvancedSettings7。");
    RunComStep("设置显示缩放", () => SetComProperty(advancedSettings, "SmartSizing", enabled));
}

// after — silently cache if control is in transition
internal void SetSmartSizing(bool enabled)
{
    _smartSizingEnabled = enabled;
    if (!IsHandleCreated || IsDisposed || ConnectedState != 1) return;
    var advancedSettings = GetComProperty(GetRequiredOcx(), "AdvancedSettings7");
    if (advancedSettings is null) return; // will be re-applied on next connect
    RunComStep("设置显示缩放", () => SetComProperty(advancedSettings, "SmartSizing", enabled));
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard SetSmartSizing against transitional control states
if (!IsHandleCreated || IsDisposed || Disposing || ConnectedState != 1)
    return; // _smartSizingEnabled is cached; will apply on next connect

Type guard

bool IsControlReadyForPropertySet() =>
    IsHandleCreated && !IsDisposed && !Disposing && ConnectedState == 1;

Try / catch

try { SetComProperty(advancedSettings, "SmartSizing", enabled); }
catch (COMException) { /* non-fatal: cached value applies on reconnect */ }

Prevention

When it happens

Trigger: SetSmartSizing is called after IsHandleCreated is true, reads AdvancedSettings7 from GetRequiredOcx(). Returns null if the AxHost handle was recreated (e.g. parent visibility change) causing GetOcx() to return a stale/null reference, or if the control is mid-disposal.

Common situations: User toggles smart-sizing while the child session window is being resized/restored, the WindowsFormsHost reparents the AxHost causing handle recreation, or the RDP session disconnected and the control is in a transitional state.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/dc8adedc9af6fb65. Report an issue: GitHub.