From the last blog post, we understand that we need new contract at the isolation boundary to route AddIn calls to and from the Host. We defined 3 new contracts IAddInRenderArgsContract IAddInSurfaceContract and IAddInColorBgraContract. As we discussed before, AddIn cannot take dependence on the Contract either. We still cannot route calls from AddIn side to the Host side. In our model, we use views and adapters to solver the problem.

 

Our solution is to create new data types in the View assembly for AddIn to use. At the same time we will provide new adapters to connect the Contracts and the view.

 

Here is our new AddInView with more data types.

 

namespace PaintDotNetAddInViews

{

    [AddInBase]

    public abstract class PDNAddInView

    {

        public abstract void Render(IAddInRenderArgs dstArgs, IAddInRenderArgs srcArgs, Rectangle[] rois, int startIndex, int length);

 

    }

 

    public interface IAddInRenderArgs

    {

        IAddInSurface GetSurface ();     

    }

 

    public interface IAddInSurface

    {

        int GetWidth();

        int GetHeight();

        IAddInColorBgra GetPointAddress(int x, int y);

       

    }

 

    public interface IAddInColorBgra

    {

        byte GetIntensityByte();

        byte GetR();

        byte GetG();

        byte GetB();

        byte GetA();

        IAddInColorBgra Next();

        IAddInColorBgra FromBgra(byte b, byte g, byte r, byte a);

    }

}

 

We exposed the similar methods in the view as in the Contract. Now we need to implement AddIn side adapters to implement data types in the AddIn view with the functionalities provided by the Contract.

 

The AddIn side adater looks like this.

 

namespace PaintDotNetAddInAdapter

{

    [AddInAdapter]

    public class PDNAddInAdapter : ContractBase, IPDNEffectContract

    {

        PDNAddInView addInView;

 

        public PDNAddInAdapter(PDNAddInView view)

        {

            addInView = view;

        }

 

 

        public void Render(IAddInRenderArgsContract dstArgs, IAddInRenderArgsContract srcArgs, Rectangle[] rois, int startIndex, int length)

        {

            addInView.Render(new ContractAddInRenderArgsAdapter(dstArgs), new ContractAddInRenderArgsAdapter(srcArgs), rois, startIndex, length);

        }      

    }

 

    public class ContractAddInRenderArgsAdapter : IAddInRenderArgs

    {

        LifetimeTokenHandle handle;

        IAddInRenderArgsContract contract;

        public ContractAddInRenderArgsAdapter(IAddInRenderArgsContract contract)

        {

            this.contract = contract;

            handle = new LifetimeTokenHandle(contract);

        }

 

        public IAddInSurface GetSurface()

        {

            return new ContractAddInSurfaceAdapter(contract.GetSurface());

        }

    }

 

    public class ContractAddInSurfaceAdapter : IAddInSurface

    {

        LifetimeTokenHandle handle;

        IAddInSurfaceContract contract;

 

        public ContractAddInSurfaceAdapter(IAddInSurfaceContract contract)

        {

            this.contract = contract;

            handle = new LifetimeTokenHandle(contract);

        }

 

        #region IAddInSurface Members

 

        public int GetWidth()

        {

            return contract.GetWidth();

        }

 

        public int GetHeight()

        {

            return contract.GetHeight();

        }

 

        public IAddInColorBgra GetPointAddress(int x, int y)

        {

           return new ContractAddInColorBgraAdapter( contract.GetPointAddress(x, y));

        }

 

        #endregion

    }

 

    public class ContractAddInColorBgraAdapter : IAddInColorBgra

    {

        LifetimeTokenHandle handle;

        IAddInColorBgraContract contract;

 

        public ContractAddInColorBgraAdapter(IAddInColorBgraContract contract)

        {

            this.contract = contract;

            handle = new LifetimeTokenHandle(contract);

        }

 

        public byte GetIntensityByte()

        {

            return contract.GetIntensityByte();

        }

 

        public byte GetR()

        {

            return contract.GetR();

        }

 

        public byte GetG()

        {

            return contract.GetG();

        }

 

        public byte GetB()

        {

            return contract.GetB();

        }

 

        public byte GetA()

        {

            return contract.GetA();

        }

 

        public IAddInColorBgra Next()

        {

            return new ContractAddInColorBgraAdapter(contract.Next());

        }

 

        public IAddInColorBgra FromBgra(byte b, byte g, byte r, byte a)

        {

            return new ContractAddInColorBgraAdapter(contract.FromBgra(b, g, r, a));

        }

    }

}

 

Most code here looks like a wrapper, except the constructors. Remember that we have discussed LifeTimeToken before. Every time we pass an IContract across the isolation boundary we need to take care of its lifetime management. Since our adapter constructors take the IContract as parameter, we have to manage its lifetime with LifetimeTokenHandle.

 

With this blog, we completed the code for the AddIn side.

 

Our next topic will cover data type adapter at the Host side.