Click here to Skip to main content
15,883,750 members
Articles / Programming Languages / C#

.NET Interprocess Communication Revisited

Rate me:
Please Sign up or sign in to vote.
4.96/5 (30 votes)
4 Jan 2010CPOL4 min read 121.5K   2.3K   111  
The XDMessaging 2.0 library provides an easy-to-use, zero configuration alternative to existing IPC implementations.
/*=============================================================================
*
*	(C) Copyright 2007, Michael Carlisle (mike.carlisle@thecodeking.co.uk)
*
*   http://www.TheCodeKing.co.uk
*  
*	All rights reserved.
*	The code and information is provided "as-is" without waranty of any kind,
*	either expresed or implied.
*
*-----------------------------------------------------------------------------
*	History:
*		11/02/2007	Michael Carlisle				Version 1.0
*       08/09/2007  Michael Carlisle                Version 1.1
*       12/12/2009  Michael Carlisle                Version 2.0
 *                  Added XDIOStream implementation which can be used from Windows Services.
*=============================================================================
*/
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using TheCodeKing.Net.Messaging.Concrete.WindowsMessaging;

namespace TheCodeKing.Net.Messaging
{
    /// <summary>
    /// The data struct that is passed between AppDomain boundaries. This is
    /// sent as a delimited string containing the channel and message.
    /// </summary>
    public struct DataGram : IDisposable
    {
        /// <summary>
        /// Stores the channel name associated with this message.
        /// </summary>
        private string channel;
        /// <summary>
        /// Stores the string message.
        /// </summary>
        private string message;
        /// <summary>
        /// The native data struct used to pass the data between applications. This
        /// contains a pointer to the data packet.
        /// </summary>
        private Native.COPYDATASTRUCT dataStruct;
        /// <summary>
        /// Gets the channel name.
        /// </summary>
        public string Channel
        {
            get
            {
                return this.channel;
            }
        }
        /// <summary>
        /// Gets the message.
        /// </summary>
        public string Message
        {
            get
            {
                return this.message;
            }
        }
        /// <summary>
        /// Constructor which creates the data gram from a message and channel name.
        /// </summary>
        /// <param name="channel">The channel through which the message will be sent.</param>
        /// <param name="message">The string message to send.</param>
        public DataGram(string channel, string message)
        {
            this.dataStruct = new Native.COPYDATASTRUCT();
            this.channel = channel;
            this.message = message;
        }
        /// <summary>
        /// Constructor creates an instance of the class from a pointer address, and expands
        /// the data packet into the originating channel name and message.
        /// </summary>
        /// <param name="lpParam">A pointer the a COPYDATASTRUCT containing information required to 
        /// expand the DataGram.</param>
        private DataGram(IntPtr lpParam)
        {
            this.dataStruct = (Native.COPYDATASTRUCT)Marshal.PtrToStructure(lpParam, typeof(Native.COPYDATASTRUCT));
            byte[] bytes = new byte[this.dataStruct.cbData];
            Marshal.Copy(this.dataStruct.lpData, bytes, 0, this.dataStruct.cbData);
            MemoryStream stream = new MemoryStream(bytes);
            BinaryFormatter b = new BinaryFormatter();
            string rawmessage = (string)b.Deserialize(stream);

            // expand data gram
            if (!string.IsNullOrEmpty(rawmessage) && rawmessage.Contains(":"))
            {
                string[] packet = rawmessage.Split(new char[] { ':' }, 2);
                this.channel = packet[0];
                this.message = packet[1];
            }
            else
            {
                this.channel = string.Empty;
                this.message = rawmessage;
            }
        }
        /// <summary>
        /// Pushes the DatGram's data into memory and returns a COPYDATASTRUCT instance with
        /// a pointer to the data so it can be sent in a Windows Message and read by another application.
        /// </summary>
        /// <returns>A struct containing the pointer to this DataGram's data.</returns>
        internal Native.COPYDATASTRUCT ToStruct()
        {
            string raw = string.Format("{0}:{1}", channel, message);

            byte[] bytes;

            // serialize data into stream
            BinaryFormatter b = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                b.Serialize(stream, raw);
                stream.Flush();
                int dataSize = (int)stream.Length;
            
                // create byte array and get pointer to mem location
                bytes = new byte[dataSize];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(bytes, 0, dataSize);
            }
            IntPtr ptrData = Marshal.AllocCoTaskMem(bytes.Length);
            Marshal.Copy(bytes, 0, ptrData, bytes.Length);

            this.dataStruct.cbData = bytes.Length;
            this.dataStruct.dwData = IntPtr.Zero;
            this.dataStruct.lpData = ptrData;

            return this.dataStruct;
        }
        /// <summary>
        /// Creates an instance of a DataGram struct from a pointer to a COPYDATASTRUCT
        /// object containing the address of the data.
        /// </summary>
        /// <param name="lpParam">A pointer to a COPYDATASTRUCT object from which the DataGram data
        /// can be derived.</param>
        /// <returns>A DataGram instance containing a message, and the channel through which
        /// it was sent.</returns>
        internal static DataGram FromPointer(IntPtr lpParam)
        {
            return new DataGram(lpParam);
        }

        /// <summary>
        /// Disposes of the unmanaged memory stored by the COPYDATASTRUCT instance
        /// when data is passed between applications.
        /// </summary>
        public void Dispose()
        {
            /// clean up unmanaged resources
            if (this.dataStruct.lpData != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(this.dataStruct.lpData);
                this.dataStruct.lpData = IntPtr.Zero;
                this.dataStruct.dwData = IntPtr.Zero;
                this.dataStruct.cbData = 0;
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United Kingdom United Kingdom
Mike Carlisle - Technical Architect with over 20 years experience in a wide range of technologies.

@TheCodeKing

Comments and Discussions