29399325d5
Wire up the previously-unimplemented Suspend, Activate, AuthenticateUser, ArchestrAUserToId, AddBufferedItem, and SetBufferedUpdateInterval command kinds in MxAccessCommandExecutor. These are real COM calls and run on the STA via the executor. - IMxAccessServer gains the 6 methods; MxAccessComServer routes them to the right interface version (Suspend/Activate -> ILMXProxyServer4 out MxStatus, AuthenticateUser -> base ILMXProxyServer, ArchestrAUserToId -> ILMXProxyServer2, AddBufferedItem/SetBufferedUpdateInterval -> ILMXProxyServer5). - Suspend/Activate surface the native MxStatus, converted to MxStatusProxy via the existing MxStatusProxyConverter. - AuthenticateUser hands the credential straight to MXAccess and never logs it; native HResult failures propagate via the dispatcher. - MxAccessSession gains matching pass-throughs; AddBufferedItem registers the item handle in the handle registry. - Unit tests (fake IMxAccessServer / fake COM object) cover each arm plus a password-non-leak assertion; existing IMxAccessServer fakes updated. No proto changes (all request/reply messages already exist).
334 lines
9.9 KiB
C#
334 lines
9.9 KiB
C#
using System;
|
|
using ArchestrA.MxAccess;
|
|
|
|
namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
|
|
|
|
/// <summary>
|
|
/// Adapter exposing MXAccess COM object methods through the <see cref="IMxAccessServer"/>
|
|
/// interface.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The supplied object must implement the typed MXAccess COM interface contract.
|
|
/// In production it is the <c>LMXProxyServerClass</c> RCW, which implements
|
|
/// <see cref="ILMXProxyServer"/> / <see cref="ILMXProxyServer3"/> /
|
|
/// <see cref="ILMXProxyServer4"/>. Tests substitute a typed fake that
|
|
/// implements <see cref="IMxAccessServer"/> directly. The earlier late-bound
|
|
/// <c>Type.InvokeMember</c> reflection fallback was removed: it bypassed the
|
|
/// typed interface contract, boxed value-type handles on every call, and only
|
|
/// ever served test doubles — a typed fake is the supported test seam now.
|
|
/// </remarks>
|
|
public sealed class MxAccessComServer : IMxAccessServer
|
|
{
|
|
private readonly object mxAccessComObject;
|
|
|
|
/// <summary>
|
|
/// Initializes the adapter with the MXAccess COM object.
|
|
/// </summary>
|
|
/// <param name="mxAccessComObject">
|
|
/// MXAccess COM object instance. Must implement either the typed
|
|
/// <see cref="ILMXProxyServer"/> COM interface family (production) or
|
|
/// <see cref="IMxAccessServer"/> directly (test fakes).
|
|
/// </param>
|
|
public MxAccessComServer(object mxAccessComObject)
|
|
{
|
|
this.mxAccessComObject = mxAccessComObject ?? throw new ArgumentNullException(nameof(mxAccessComObject));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int Register(string clientName)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.Register(clientName);
|
|
}
|
|
|
|
return AsProxyServer().Register(clientName);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Unregister(int serverHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.Unregister(serverHandle);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().Unregister(serverHandle);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int AddItem(
|
|
int serverHandle,
|
|
string itemDefinition)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.AddItem(serverHandle, itemDefinition);
|
|
}
|
|
|
|
return AsProxyServer().AddItem(serverHandle, itemDefinition);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int AddItem2(
|
|
int serverHandle,
|
|
string itemDefinition,
|
|
string itemContext)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.AddItem2(serverHandle, itemDefinition, itemContext);
|
|
}
|
|
|
|
return AsProxyServer3().AddItem2(serverHandle, itemDefinition, itemContext);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void RemoveItem(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.RemoveItem(serverHandle, itemHandle);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().RemoveItem(serverHandle, itemHandle);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Advise(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.Advise(serverHandle, itemHandle);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().Advise(serverHandle, itemHandle);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void UnAdvise(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.UnAdvise(serverHandle, itemHandle);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().UnAdvise(serverHandle, itemHandle);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void AdviseSupervisory(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.AdviseSupervisory(serverHandle, itemHandle);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer4().AdviseSupervisory(serverHandle, itemHandle);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public object Suspend(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.Suspend(serverHandle, itemHandle);
|
|
}
|
|
|
|
AsProxyServer4().Suspend(serverHandle, itemHandle, out MxStatus status);
|
|
return status;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public object Activate(
|
|
int serverHandle,
|
|
int itemHandle)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.Activate(serverHandle, itemHandle);
|
|
}
|
|
|
|
AsProxyServer4().Activate(serverHandle, itemHandle, out MxStatus status);
|
|
return status;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int AuthenticateUser(
|
|
int serverHandle,
|
|
string verifyUser,
|
|
string verifyUserPassword)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.AuthenticateUser(serverHandle, verifyUser, verifyUserPassword);
|
|
}
|
|
|
|
return AsProxyServer().AuthenticateUser(serverHandle, verifyUser, verifyUserPassword);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int ArchestrAUserToId(
|
|
int serverHandle,
|
|
string userIdGuid)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.ArchestrAUserToId(serverHandle, userIdGuid);
|
|
}
|
|
|
|
return AsProxyServer2().ArchestrAUserToId(serverHandle, userIdGuid);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public int AddBufferedItem(
|
|
int serverHandle,
|
|
string itemDefinition,
|
|
string itemContext)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
return typedFake.AddBufferedItem(serverHandle, itemDefinition, itemContext);
|
|
}
|
|
|
|
return AsProxyServer5().AddBufferedItem(serverHandle, itemDefinition, itemContext);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SetBufferedUpdateInterval(
|
|
int serverHandle,
|
|
int updateIntervalMilliseconds)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.SetBufferedUpdateInterval(serverHandle, updateIntervalMilliseconds);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer5().SetBufferedUpdateInterval(serverHandle, updateIntervalMilliseconds);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Write(
|
|
int serverHandle,
|
|
int itemHandle,
|
|
object? value,
|
|
int userId)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.Write(serverHandle, itemHandle, value, userId);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().Write(serverHandle, itemHandle, value!, userId);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Write2(
|
|
int serverHandle,
|
|
int itemHandle,
|
|
object? value,
|
|
object? timestamp,
|
|
int userId)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.Write2(serverHandle, itemHandle, value, timestamp, userId);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer4().Write2(serverHandle, itemHandle, value!, timestamp!, userId);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void WriteSecured(
|
|
int serverHandle,
|
|
int itemHandle,
|
|
int currentUserId,
|
|
int verifierUserId,
|
|
object? value)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.WriteSecured(serverHandle, itemHandle, currentUserId, verifierUserId, value);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer().WriteSecured(serverHandle, itemHandle, currentUserId, verifierUserId, value!);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void WriteSecured2(
|
|
int serverHandle,
|
|
int itemHandle,
|
|
int currentUserId,
|
|
int verifierUserId,
|
|
object? value,
|
|
object? timestamp)
|
|
{
|
|
if (mxAccessComObject is IMxAccessServer typedFake)
|
|
{
|
|
typedFake.WriteSecured2(serverHandle, itemHandle, currentUserId, verifierUserId, value, timestamp);
|
|
return;
|
|
}
|
|
|
|
AsProxyServer4().WriteSecured2(serverHandle, itemHandle, currentUserId, verifierUserId, value!, timestamp!);
|
|
}
|
|
|
|
private ILMXProxyServer AsProxyServer()
|
|
{
|
|
return mxAccessComObject as ILMXProxyServer
|
|
?? throw new InvalidOperationException(
|
|
$"MXAccess COM object of type '{mxAccessComObject.GetType().FullName}' does not implement "
|
|
+ $"{nameof(ILMXProxyServer)} or {nameof(IMxAccessServer)}.");
|
|
}
|
|
|
|
private ILMXProxyServer2 AsProxyServer2()
|
|
{
|
|
return mxAccessComObject as ILMXProxyServer2
|
|
?? throw new InvalidOperationException(
|
|
$"MXAccess COM object of type '{mxAccessComObject.GetType().FullName}' does not implement "
|
|
+ $"{nameof(ILMXProxyServer2)} or {nameof(IMxAccessServer)}.");
|
|
}
|
|
|
|
private ILMXProxyServer3 AsProxyServer3()
|
|
{
|
|
return mxAccessComObject as ILMXProxyServer3
|
|
?? throw new InvalidOperationException(
|
|
$"MXAccess COM object of type '{mxAccessComObject.GetType().FullName}' does not implement "
|
|
+ $"{nameof(ILMXProxyServer3)} or {nameof(IMxAccessServer)}.");
|
|
}
|
|
|
|
private ILMXProxyServer4 AsProxyServer4()
|
|
{
|
|
return mxAccessComObject as ILMXProxyServer4
|
|
?? throw new InvalidOperationException(
|
|
$"MXAccess COM object of type '{mxAccessComObject.GetType().FullName}' does not implement "
|
|
+ $"{nameof(ILMXProxyServer4)} or {nameof(IMxAccessServer)}.");
|
|
}
|
|
|
|
private ILMXProxyServer5 AsProxyServer5()
|
|
{
|
|
return mxAccessComObject as ILMXProxyServer5
|
|
?? throw new InvalidOperationException(
|
|
$"MXAccess COM object of type '{mxAccessComObject.GetType().FullName}' does not implement "
|
|
+ $"{nameof(ILMXProxyServer5)} or {nameof(IMxAccessServer)}.");
|
|
}
|
|
}
|