Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

C# Wrapper for Mailslots

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
19 Jul 2013CPOL 21.6K   7   2
A wrapper for Mailslots in C#
As .NET standard libraries do not provide classes for Mailslot operations and wrappers that I found did not satisfy my requirements, here is my implementation and how you can use it:

Introduction

Mailslot is a simple type of inter-process communication on Windows platform. It is one-way fire-and-forget no-confirmation type of communication: a server opens a slot and multiple clients can send messages to it.

.NET standard libraries do not provide classes for Mailslot operations and wrappers that I found did not satisfy my requirements - simplicity and elegance. :)

This is my implementation, here is how you can use it:

C#
using (var server = new MailslotServer("MailslotName"))
{
    var msg = server.GetNextMessage();

    if (msg != null)
    {
        DoWork();
    }

    Thread.Sleep(1000);
}

using (var client = new MailslotClient("MailslotName"))
{
    client.SendMessage("hello server :)");
}

And the code...

C#
[SuppressUnmanagedCodeSecurity]
public static class Mailslot
{
    public const int MailslotNoMessage = -1;

    [Flags]
    public enum FileDesiredAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000
    }

    [Flags]
    public enum FileShareMode : uint
    {
        Zero = 0x00000000,
        FileShareDelete = 0x00000004,
        FileShareRead = 0x00000001,
        FileShareWrite = 0x00000002
    }

    public enum FileCreationDisposition : uint
    {
        CreateNew = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5
    }

    [SecurityCritical(SecurityCriticalScope.Everything)]
    [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
    [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
    public sealed class SafeMailslotHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeMailslotHandle() : base(true){}
        public SafeMailslotHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
        {
            base.SetHandle(preexistingHandle);
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(base.handle);
        }
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateMailslot(string mailslotName,
                                                uint nMaxMessageSize, int lReadTimeout,
                                                IntPtr securityAttributes);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetMailslotInfo(SafeMailslotHandle hMailslot,
                                                IntPtr lpMaxMessageSize, 
                                                out int lpNextSize, out int lpMessageCount,
                                                IntPtr lpReadTimeout);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ReadFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToRead, 
                                        out int numBytesRead,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool WriteFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToWrite, 
                                        out int numBytesWritten,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateFile(string fileName,
                                        FileDesiredAccess desiredAccess, 
                                        FileShareMode shareMode,
                                        IntPtr securityAttributes,
                                        FileCreationDisposition creationDisposition,
                                        int flagsAndAttributes, IntPtr hTemplateFile);
}

public class MailslotServer : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;

    public MailslotServer(string name)
    {
        _handle = Mailslot.CreateMailslot(@"\\.\mailslot\" + name, 0, 0, IntPtr.Zero);
        if (_handle.IsInvalid) throw new Win32Exception();
    }

    public string GetNextMessage()
    {
        int messageBytes;
        int bytesRead;
        int messages;

        if (!Mailslot.GetMailslotInfo(_handle, IntPtr.Zero, out messageBytes, 
                     out messages, IntPtr.Zero)) throw new Win32Exception();

        if (messageBytes == Mailslot.MailslotNoMessage) return null;

        var bBuffer = new byte[messageBytes];

        if (!Mailslot.ReadFile( _handle, bBuffer, messageBytes, out bytesRead, 
             IntPtr.Zero) || bytesRead == 0) throw new Win32Exception();

        return Encoding.Unicode.GetString(bBuffer);
    }

    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }
}

public class MailslotClient : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;
    private readonly string _name;
    private readonly string _machine;

    public MailslotClient(string name) : this(name, ".") { }
    public MailslotClient(string name, string machine)
    {
        _name = name;
        _machine = machine;
    }

    public void SendMessage(string msg)
    {
        if (_handle == null) CreateHandle();

        int bytesWritten;

        byte[] bMessage = Encoding.Unicode.GetBytes(msg);

        bool succeeded = Mailslot.WriteFile(_handle, bMessage, 
             bMessage.Length, out bytesWritten, IntPtr.Zero);

        if (!succeeded || bMessage.Length != bytesWritten)
        {
            if (_handle != null) _handle.Close();
            _handle = null;

            throw new Win32Exception();
        }
    }
    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }

    private void CreateHandle()
    {
        _handle = Mailslot.CreateFile(
            @"\\" + _machine + @"\mailslot\" + _name,
            Mailslot.FileDesiredAccess.GenericWrite,
            Mailslot.FileShareMode.FileShareRead,
            IntPtr.Zero,
            Mailslot.FileCreationDisposition.OpenExisting,
            0,
            IntPtr.Zero);

        if (_handle.IsInvalid) throw new Win32Exception();
            
    }
}

History

  • 19th July, 2013: Initial version

License

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


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCleanup? Pin
Greg B Roberts12-Oct-15 19:44
Greg B Roberts12-Oct-15 19:44 
Questionnamspaces Pin
ITSTH15-Aug-14 3:20
ITSTH15-Aug-14 3:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.