Call IModelDoc2::Access3rdPartyStream extension method to access the 3rd party stream. Pass the boolean parameter to read or write stream.

use this approach when it is required to store a single structure at the model.

Stream Access Handler

To simplify the handling of the stream lifecycle, use the Documents Manager API from the SwEx.AddIn framework:

using CodeStack.SwEx.AddIn;
using CodeStack.SwEx.AddIn.Attributes;
using CodeStack.SwEx.AddIn.Base;
using CodeStack.SwEx.AddIn.Core;
using CodeStack.SwEx.AddIn.Enums;
using SolidWorks.Interop.sldworks;
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Serialization;

namespace CodeStack.SwEx
{
    [AutoRegister]
    [ComVisible(true), Guid("64684CEF-131C-4F08-88F7-B3C3BAA7004E")]
    public class ThirdPartyDataAddIn : SwAddInEx
    {
        private IDocumentsHandler<DocumentHandler> m_StreamDocHandler;

        public override bool OnConnect()
        {
            m_StreamDocHandler = CreateDocumentsHandler();
            m_StreamDocHandler.HandlerCreated += OnStreamHandlerCreated;
            return true;
        }

        private void OnStreamHandlerCreated(DocumentHandler doc)
        {
            doc.Access3rdPartyData += OnAccess3rdPartyStream;
        }

        private void OnAccess3rdPartyStream(DocumentHandler docHandler, Access3rdPartyDataState_e state)
        {
            switch (state)
            {
                case Access3rdPartyDataState_e.StreamRead:
                    LoadFromStream(docHandler.Model);
                    break;

                case Access3rdPartyDataState_e.StreamWrite:
                    SaveToStream(docHandler.Model);
                    break;
            }
        }
    }
}

Reading data

IThirdPartyStreamHandler::Stream property returns null for the stream which not exists on reading.

private const string STREAM_NAME = "CodeStackStream";

public class StreamData
{
    public string Prp1 { get; set; }
    public double Prp2 { get; set; }
}

private StreamData m_StreamData;

private void LoadFromStream(IModelDoc2 model)
{
    using (var streamHandler = model.Access3rdPartyStream(STREAM_NAME, false))
    {
        if (streamHandler.Stream != null)
        {
            using (var str = streamHandler.Stream)
            {
                var xmlSer = new XmlSerializer(typeof(StreamData));
                m_StreamData = xmlSer.Deserialize(str) as StreamData;
            }
        }
    }
}

Writing data

IThirdPartyStreamHandler::Stream will always return the pointer to the stream (stream is automatically created if it doesn’t exist).

private const string STREAM_NAME = "CodeStackStream";

public class StreamData
{
    public string Prp1 { get; set; }
    public double Prp2 { get; set; }
}

private StreamData m_StreamData;

private void SaveToStream(IModelDoc2 model)
{
    using (var streamHandler = model.Access3rdPartyStream(STREAM_NAME, true))
    {
        using (var str = streamHandler.Stream)
        {
            var xmlSer = new XmlSerializer(typeof(StreamData));

            xmlSer.Serialize(str, m_StreamData);
        }
    }
}