Files
mxaccess/rust/crates/mxaccess-rpc/Cargo.toml
T
Joseph Doherty cf9dbaf568
rust / build / test / clippy / fmt (push) Has been cancelled
[F6] mxaccess-rpc: ComObjRefProvider port via windows-rs (CoMarshalInterface)
New module crates/mxaccess-rpc/src/com_objref_provider.rs gated on
cfg(all(windows, feature = "windows-com")). Pulls windows = "0.59"
(features Win32_Foundation + Win32_System_Com +
Win32_System_Com_Marshal + Win32_System_Com_StructuredStorage +
Win32_System_Memory) as an optional dep behind the existing
windows-com feature; default footprint stays slim.

Public API mirrors ComObjRefProvider.cs 1:1: MarshalContext enum
(InProcess / Local / DifferentMachine wrapping the MSHCTX_* newtype
constants), clsid_from_prog_id, marshal_activated_iunknown_objref
(activates via CoCreateInstance with INPROC | LOCAL | REMOTE then
marshals), marshal_iunknown_objref (uses IUnknown::IID),
marshal_interface_objref (CoMarshalInterface over an HGlobal-backed
IStream).

All `unsafe` is internal to the module — public API exposes only
typed Rust values (Vec<u8>, GUID, ProviderError), no raw pointers /
HRESULTs / lifetime-bound interface pointers leak. Each unsafe block
carries an inline SAFETY comment naming the invariants being upheld.

Per-thread COM init via thread-local OnceLock<()>: lazy
CoInitializeEx(MULTITHREADED) on first call; S_FALSE (already
initialised) and RPC_E_CHANGED_MODE (thread is STA) treated as
success — matches the .NET runtime's tolerant apartment behaviour.

ProviderError enumerates the four documented failure modes plus the
apartment-init pre-check: UnknownProgId / ActivationFailed /
MarshalFailed / GlobalLockFailed / ApartmentInitFailed.

4 offline tests: MarshalContext → MSHCTX_* mapping, ensure_apartment
idempotence, clsid_from_prog_id returns UnknownProgId for fake
ProgIDs, marshal_activated short-circuits at the resolution stage.

1 live test (#[ignore], gated on MX_LIVE): activates the real
NmxSvc.NmxService, marshals the proxy's IUnknown via
CoMarshalInterface, then parses the resulting blob via
ComObjRef::parse and asserts non-zero OXID + IPID. Passes against
the AVEVA install on this host.

Workspace tests: mxaccess-rpc went 179 → 183 (+4). All other crates
unchanged.

Unblocks F12 (NmxClient::create — the auto-resolving
COM-activation factory): the underlying primitive
(marshal_activated_iunknown_objref) now exists; remaining work is
threading the windows-com feature through mxaccess-nmx and chaining
ComObjRef::parse → resolve_oxid_with_managed_ntlm_packet_integrity →
RemQueryInterface. design/followups.md F12 updated with a revised
"Resolves when" reflecting that F6's blocker is gone.

Closes F6 in design/followups.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:11:33 -04:00

44 lines
1.3 KiB
TOML

[package]
name = "mxaccess-rpc"
description = "DCE/RPC PDU codec + NTLMv2 + OBJREF + OXID resolution + RemQI for the NMX transport."
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
authors.workspace = true
[dependencies]
thiserror = { workspace = true }
tokio = { workspace = true }
hmac = "0.12"
md-5 = "0.10"
md4 = "0.10"
rc4 = "0.2"
rand = "0.8"
# F6 — Win32 OBJREF emitter via CoMarshalInterface. Optional, gated by the
# `windows-com` feature so the default footprint stays slim. windows-rs
# pulls a small set of submodules — Win32_System_Com for IUnknown / IStream
# / CoCreateInstance / CoMarshalInterface, Win32_System_Memory for
# GlobalLock / GlobalSize, Win32_System_Ole for the historical
# CreateStreamOnHGlobal / GetHGlobalFromStream re-exports.
windows = { version = "0.59", features = [
"Win32_Foundation",
"Win32_System_Com",
"Win32_System_Com_Marshal",
"Win32_System_Com_StructuredStorage",
"Win32_System_Memory",
], optional = true }
[features]
default = []
# Gates the Win32 OBJREF emitter port (`com_objref_provider` module). The
# module itself is `cfg(windows)`-gated so non-Windows builds with the
# feature on stay green (the `windows` crate compiles to stubs on
# non-Windows targets).
windows-com = ["dep:windows"]
[lints]
workspace = true