R1.4 GetHistorianInfo: bounded out on 2020 WCF (named-value-only, no struct)
Captured the native HistorianAccess.GetHistorianInfo(out HistorianInfo, out err) and decoded the wire: over 2020 WCF, GETHI is a named-value query whose only working key is "HistorianVersion" (response ~30 bytes = the version string). Probed 7 storage-mode key names -> all ok=False/err. The 518-byte HISTORIAN_INFO struct + EventStorageMode@514 is the 2023R2 HCAL-native/gRPC model (confirmed from the decompiled 2023R2 source); on 2020 the native client derives the mode outside the WCF wire. Version is already exposed (ProbeAsync/GetRuntimeParameterAsync), so no hollow GetHistorianInfoAsync is shipped (same disposition as R1.3 timezone). This completes the reachable 2020-WCF M1 read surface; remaining M1 = config writes (gated on explicit request) or gRPC/2023R2-only items. RE aids kept: harness `historian-info` scenario, Capture-HistorianInfo.ps1, decode-historian-info-capture.py, and StringHandleProbeDiagnosticTests .GETHI_CandidateInfoNames (asserts the named-value-only finding; gated). Docs: wcf-historian-info.md (new) + roadmap/matrix/wall-doc updates. 230 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -246,6 +246,33 @@ internal static class Program
|
||||
}));
|
||||
return 0;
|
||||
}
|
||||
else if (openSuccess && status.ConnectedToServer && IsHistorianInfoScenario(scenario))
|
||||
{
|
||||
// R1.4 capture: drive HistorianAccess.GetHistorianInfo(out HistorianInfo, out error)
|
||||
// so instrument-wcf-{write,read}message can observe the WCF GETHI pRequestBuff that
|
||||
// returns the full 518-byte HISTORIAN_INFO struct (version@0 + EventStorageMode@514),
|
||||
// distinct from the named-value "HistorianVersion" request. Pure status read.
|
||||
MethodInfo getInfoMethod = accessType.GetMethods()
|
||||
.First(m => m.Name == "GetHistorianInfo"
|
||||
&& m.GetParameters().Length == 2
|
||||
&& m.GetParameters()[0].ParameterType.IsByRef
|
||||
&& m.GetParameters()[1].ParameterType.IsByRef);
|
||||
|
||||
object infoError = Activator.CreateInstance(errorType)!;
|
||||
object?[] infoArgs = new object?[] { null, infoError };
|
||||
WriteRuntimeMethodPointerSnapshot(assembly, runtimeMethodPointerOutput, runtimeMethodPointerFilters, repoRoot, scenario, "before-get-historian-info");
|
||||
bool infoOk = (bool)getInfoMethod.Invoke(access, infoArgs)!;
|
||||
|
||||
Console.WriteLine(Serialize(new
|
||||
{
|
||||
Scenario = scenario,
|
||||
GetHistorianInfoReturned = infoOk,
|
||||
HistorianInfoType = getInfoMethod.GetParameters()[0].ParameterType.GetElementType()?.FullName,
|
||||
HistorianInfo = infoArgs[0] is null ? null : SnapshotObject(infoArgs[0]!),
|
||||
Error = SnapshotObject(infoArgs[1]!),
|
||||
}));
|
||||
return 0;
|
||||
}
|
||||
else if (openSuccess && status.ConnectedToServer && IsEventSendScenario(scenario))
|
||||
{
|
||||
// R2.1 capture: drive AddStreamedValue(HistorianEvent) and let instrument-wcf-*
|
||||
@@ -1502,6 +1529,19 @@ internal static class Program
|
||||
|| scenario.Equals("runtime-parameter", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Historian-info scenario (R1.4 capture): opens a normal authenticated process connection and
|
||||
/// calls <c>GetHistorianInfo(out HistorianInfo, out error)</c> so instrument-wcf-{write,read}message
|
||||
/// can observe the WCF GETHI <c>pRequestBuff</c>/<c>pResponseBuff</c> that returns the full
|
||||
/// 518-byte HISTORIAN_INFO struct (version@0 + EventStorageMode@514). Pure status read.
|
||||
/// </summary>
|
||||
private static bool IsHistorianInfoScenario(string scenario)
|
||||
{
|
||||
return scenario.Equals("historian-info", StringComparison.OrdinalIgnoreCase)
|
||||
|| scenario.Equals("hist-info", StringComparison.OrdinalIgnoreCase)
|
||||
|| scenario.Equals("gethi", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL-command scenario (R1.1 capture): opens a normal authenticated process connection and
|
||||
/// calls <c>ExecuteSqlCommand</c> (Retr.ExeC + Retr.GetR) so the string-handle SQL surface
|
||||
|
||||
Reference in New Issue
Block a user