Files
histsdk/docs/reverse-engineering/wcf-string-handle-wall.md
T
Joseph Doherty 84ec175f76 docs: map the 2020 WCF string-handle wall (R1.4 GETHI blocked)
Probed R1.4 GetHistorianInfo (GETHI) live against the local 2020 server.
GETHI returns native error type 4 / code 1 for the exact native request shape
across 5 handle formats (storage GUID, context GUID, uint decimal/X8/0x-hex)
even with Stat.GetV ×2 priming. Its result is discarded (TryRun) in the only
place it's used, so it was never actually verified to return data managed-side.

This confirms a structural boundary on the 2020 WCF surface: ops taking a uint
client handle work (the proven read/browse/metadata/status/event surface);
ops taking a string GUID handle (ExeC, QTB, QTG, GETHI, GetTepByNm, ...) are
blocked behind an unmapped native session/filter registration. Every remaining
M1 *read* item (R1.1/R1.4/R1.5/R1.6) is string-handle -> all gated on that one
RE target. Reachable uint-handle items: R1.7 event filters, R1.8/R1.9 summary
modes.

New: docs/reverse-engineering/wcf-string-handle-wall.md (full dichotomy + table).
Roadmap R1.4/R1.5/R1.6 struck through; reachable items re-pointed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:32:15 -04:00

3.5 KiB
Raw Blame History

The 2020 WCF string-handle wall (2026-06-20)

Live-probing the local Historian 2020 (WCF, port 32568) for HCAL roadmap M1 surfaced a clean structural boundary on what the pure-managed client can call. It explains why R1.1/R1.4/R1.5 all fail and identifies the single RE target that unblocks the rest of the M1 read surface.

The dichotomy

Retrieval/Status/History ops split by the type of their first (handle) parameter:

Handle type Examples Status on 2020 WCF
uint client handle (Open2 output) StartQuery2, GetNextQueryResultBuffer2, IsOriginalAllowed, GetTagInfosFromName/GetTagInfoFromName (GetTgByNm), GetSystemParameter, StartEventQuery, GetNextEventQueryResultBuffer, RegisterTags2, EnsureTags2, UpdateClientStatus3 work — the proven read/browse/metadata/status-param/event/write surface
string GUID handle ExecuteSqlCommand (ExeC), StartTagQuery (QTB), QueryTag (QTG), GetHistorianInfo (GETHI), GetTagExtendedPropertiesFromName (GetTepByNm), GetTagInfosFromName2 (GetTgByNm2), GetTagidsByTagnameAndSource blocked — native error type 4, code 51 (InvalidParameter) or 1 (Failure)

Evidence (this probe + prior notes)

  • ExeC → type 4 / code 51 for every handle variant (storageGuid, contextGuid). Matches implementation-status.md ~982 / ~1404 ("StartTagQuery depends on earlier native session/filter registration … do not wire through guessed calls").
  • GETHI (HistorianVersion param query — the exact native request shape from BuildGetHistorianInfoRequest, with Stat.GetV ×2 priming) → type 4 / code 1 for all five handle formats tried: storage-session GUID, context GUID, uint as decimal, uint as X8 hex, uint as 0x-hex. In the only place GETHI is used (the event-priming chain) its result is wrapped in TryRun and discarded, so there was never evidence it actually returns data from the managed client.
  • GetTepByNm / QTB / QTG / GetTgByNm2 all take a string handle → same family.

Why

The string-handle ops are keyed off a native-side session/filter registration that the C++ client performs but the managed replay does not reproduce. The uint client handle is the Open2 session token the server already trusts; the string GUID handle indexes a different per-service registration table that stays empty unless the native priming is replicated faithfully. Stat.GetV ×2 alone is insufficient.

Consequence for the roadmap

Every remaining M1 read item is a string-handle op:

  • R1.1 ExecuteSqlCommandAsync (ExeC) — blocked
  • R1.4 GetHistorianInfoAsync (GETHI) — blocked
  • R1.5 extended-property read (GetTepByNm) — blocked (string handle, confirmed)
  • R1.6 localized-property read — same family

So M1 read-surface completion on 2020 WCF is gated entirely behind one RE target: the native session/filter registration for string-handle ops. Reverse-engineer it once and the whole family unlocks. Until then, the alternatives are:

  1. RE the registration — instrument the native CRetrievalConnectionWCF / CStatusConnectionWCF priming between Open2 and the first successful string-handle call (capture-tier; the highest-leverage single RE task for M1).
  2. 2023 R2 gRPC server — these ops are first-class on the gRPC front door, where the handle/envelope differs and the registration wall may not apply.

Do not ship any string-handle op via guessed calls (project discipline: "leave them throwing until evidence supports an implementation").