File: System\Transactions\DtcProxyShim\TransactionShim.cs
Web Access
Project: src\src\runtime\src\libraries\System.Transactions.Local\src\System.Transactions.Local.csproj (System.Transactions.Local)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Transactions.DtcProxyShim.DtcInterfaces;
using System.Transactions.Oletx;

namespace System.Transactions.DtcProxyShim;

internal sealed class TransactionShim
{
    private readonly DtcProxyShimFactory _shimFactory;
    private readonly TransactionNotifyShim _transactionNotifyShim;

    internal ITransaction Transaction { get; set; }

    internal TransactionShim(DtcProxyShimFactory shimFactory, TransactionNotifyShim notifyShim, ITransaction transaction)
    {
        _shimFactory = shimFactory;
        _transactionNotifyShim = notifyShim;
        Transaction = transaction;
    }

    public void Commit()
        => Transaction.Commit(false, OletxXacttc.XACTTC_ASYNC, 0);

    public void Abort()
        => Transaction.Abort(IntPtr.Zero, false, false);

    public void CreateVoter(OletxPhase1VolatileEnlistmentContainer managedIdentifier, out VoterBallotShim voterBallotShim)
    {
        var voterNotifyShim = new VoterNotifyShim(_shimFactory, managedIdentifier);
        var voterShim = new VoterBallotShim(voterNotifyShim);
        _shimFactory.VoterFactory.Create(Transaction, voterNotifyShim, out ITransactionVoterBallotAsync2 voterBallot);
        voterShim.VoterBallotAsync2 = voterBallot;
        voterBallotShim = voterShim;
    }

    public void Export(byte[] whereabouts, out byte[] cookieBuffer)
    {
        _shimFactory.ExportFactory.Create((uint)whereabouts.Length, whereabouts, out ITransactionExport export);

        uint cookieSizeULong = 0;

        OletxHelper.Retry(() => export.Export(Transaction, out cookieSizeULong));

        var cookieSize = (uint)cookieSizeULong;
        var buffer = new byte[cookieSize];
        uint bytesUsed = 0;

        OletxHelper.Retry(() => export.GetTransactionCookie(Transaction, cookieSize, buffer, out bytesUsed));

        cookieBuffer = buffer;
    }

    public void GetITransactionNative(out ITransaction transactionNative)
    {
        var cloner = (ITransactionCloner)Transaction;
        cloner.CloneWithCommitDisabled(out ITransaction returnTransaction);

        transactionNative = returnTransaction;
    }

    public byte[] GetPropagationToken()
    {
        ITransactionTransmitter transmitter = _shimFactory.GetCachedTransmitter(Transaction);

        try
        {
            transmitter.GetPropagationTokenSize(out uint propagationTokenSizeULong);

            var propagationTokenSize = (int)propagationTokenSizeULong;
            var propagationToken = new byte[propagationTokenSize];

            transmitter.MarshalPropagationToken((uint)propagationTokenSize, propagationToken, out uint propagationTokenSizeUsed);

            return propagationToken;
        }
        finally
        {
            _shimFactory.ReturnCachedTransmitter(transmitter);
        }
    }

    public void Phase0Enlist(object managedIdentifier, out Phase0EnlistmentShim phase0EnlistmentShim)
    {
        var phase0Factory = (ITransactionPhase0Factory)Transaction;
        var phase0NotifyShim = new Phase0NotifyShim(_shimFactory, managedIdentifier);
        var phase0Shim = new Phase0EnlistmentShim(phase0NotifyShim);

        phase0Factory.Create(phase0NotifyShim, out ITransactionPhase0EnlistmentAsync phase0Async);
        phase0Shim.Phase0EnlistmentAsync = phase0Async;

        phase0Async.Enable();
        phase0Async.WaitForEnlistment();

        phase0EnlistmentShim = phase0Shim;
    }
}