probe: InitializeConsumer required — provider visible after, alarms still absent
InitializeConsumer was the missing call. Adding it before
RegisterConsumer makes the \Galaxy! provider appear in
GetProviders (status 0 -> 100 within 500ms). Without Initialize,
GetProviders returns an empty list even though everything else
returns rc=0 (success).
Probe trace 2026-05-01:
InitializeConsumer -> 0
RegisterConsumer -> 0
GetProviders [after Register] -> count=0 list=[]
Subscribe('\Galaxy!') -> 0
GetProviders [after Subscribe] -> count=1 list=[ 0 \Galaxy!]
GetProviders [poll #1] -> count=1 list=[100 \Galaxy!]
Despite the provider being at "100% query complete" for the
entire 60s window, GetStatistics continued to report
total=0 active=0 codes=[7] -- no alarm transitions reached the
consumer even with a System Platform script flipping
TestMachine_001.TestAlarm001 every 10s during the run.
So the consumer chain works end-to-end. What's missing is alarm
traffic from the producer side. The next discriminator is
whether ObjectViewer (or another live consumer) sees the alarm
fire while the script runs.
API-ordering bug fix to apply to PR A.5's AlarmClientConsumer
regardless of how A.2 lands: AlarmClientConsumer.Subscribe
should call InitializeConsumer before RegisterConsumer (currently
omits Initialize entirely, which means the provider chain is
never visible from the worker either). That fix lifts a
fundamental bug independent of the polling-vs-callback question.
Probe changes:
- Added InitializeConsumer call before RegisterConsumer.
- Added LogProviders helper that logs only on change; called
after Register, after Subscribe, and on every poll. Easier
to spot when the provider chain transitions from empty to
populated.
- Restored Skip-gating after run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -231,6 +231,22 @@ public sealed class AlarmClientWmProbeTests : IDisposable
|
||||
try
|
||||
{
|
||||
client = new AlarmClient();
|
||||
|
||||
// Try InitializeConsumer first — separate from RegisterConsumer
|
||||
// per the discovered API surface; previous probe runs skipped
|
||||
// it. Some AVEVA managed-client patterns require Initialize
|
||||
// before Register; others reverse the order. Try Initialize
|
||||
// first; on failure proceed to Register.
|
||||
try
|
||||
{
|
||||
int init = client.InitializeConsumer("AlarmProbe.Tests");
|
||||
Log($"InitializeConsumer -> {init}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"InitializeConsumer threw: {ex.GetType().Name}: {ex.Message}");
|
||||
}
|
||||
|
||||
int register = client.RegisterConsumer(
|
||||
hWnd: probeWindow.ToInt32(),
|
||||
szProductName: "AlarmProbe",
|
||||
@@ -239,18 +255,7 @@ public sealed class AlarmClientWmProbeTests : IDisposable
|
||||
bRetainHiddenAlarms: false);
|
||||
Log($"RegisterConsumer -> {register}");
|
||||
|
||||
// Discover what providers AVEVA sees before subscribing, so we
|
||||
// can spot a wrong subscription expression up front.
|
||||
try
|
||||
{
|
||||
var providers = new System.Collections.Generic.List<string>();
|
||||
int gp = client.GetProviders(providers);
|
||||
Log($"GetProviders -> rc={gp} count={providers.Count} list=[{string.Join(", ", providers)}]");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"GetProviders threw: {ex.GetType().Name}: {ex.Message}");
|
||||
}
|
||||
LogProviders(client, "after Register");
|
||||
|
||||
int subscribe = client.Subscribe(
|
||||
szSubscription: SubscriptionExpression,
|
||||
@@ -261,6 +266,8 @@ public sealed class AlarmClientWmProbeTests : IDisposable
|
||||
FilterSpecification: eAlarmFilterState.asNone);
|
||||
Log($"Subscribe('{SubscriptionExpression}') -> {subscribe}");
|
||||
|
||||
LogProviders(client, "after Subscribe");
|
||||
|
||||
// 3c. Pump for the configured duration. Log every message we see
|
||||
// (filtered light to avoid noise from WM_PAINT / WM_TIMER /
|
||||
// WM_GETICON spam from typical pumps). Poll GetStatistics on
|
||||
@@ -290,6 +297,7 @@ public sealed class AlarmClientWmProbeTests : IDisposable
|
||||
if (DateTime.UtcNow >= nextPoll)
|
||||
{
|
||||
PollGetStatistics(client, ++pollCount);
|
||||
LogProviders(client, $"poll #{pollCount}");
|
||||
nextPoll = DateTime.UtcNow + PollInterval;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
@@ -316,6 +324,26 @@ public sealed class AlarmClientWmProbeTests : IDisposable
|
||||
}
|
||||
|
||||
private string lastStatsSummary = string.Empty;
|
||||
private string lastProvidersSummary = string.Empty;
|
||||
|
||||
private void LogProviders(AlarmClient client, string when)
|
||||
{
|
||||
try
|
||||
{
|
||||
var providers = new System.Collections.Generic.List<string>();
|
||||
int rc = client.GetProviders(providers);
|
||||
string summary = $"count={providers.Count} list=[{string.Join(", ", providers)}]";
|
||||
if (summary != lastProvidersSummary)
|
||||
{
|
||||
Log($"GetProviders [{when}] -> rc={rc} {summary} (changed)");
|
||||
lastProvidersSummary = summary;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"GetProviders [{when}] threw: {ex.GetType().Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drive an MxAccess write to <see cref="TriggerTagReference"/> with the
|
||||
|
||||
Reference in New Issue
Block a user